Skip to content

Commit cdc01a1

Browse files
František Kučeratiwai
authored andcommitted
ALSA: usb-audio: Add mixer support for Pioneer DJ DJM-250MK2
This patch extends support for DJM-250MK2 and allows mapping playback and capture channels to available sources. Configures the card through USB commands. Signed-off-by: František Kučera <[email protected]> Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Takashi Iwai <[email protected]>
1 parent 6564d0a commit cdc01a1

File tree

1 file changed

+213
-0
lines changed

1 file changed

+213
-0
lines changed

sound/usb/mixer_quirks.c

Lines changed: 213 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2602,6 +2602,216 @@ static int snd_bbfpro_controls_create(struct usb_mixer_interface *mixer)
26022602
return 0;
26032603
}
26042604

2605+
/*
2606+
* Pioneer DJ DJM-250MK2 and maybe other DJM models
2607+
*
2608+
* For playback, no duplicate mapping should be set.
2609+
* There are three mixer stereo channels (CH1, CH2, AUX)
2610+
* and three stereo sources (Playback 1-2, Playback 3-4, Playback 5-6).
2611+
* Each channel should be mapped just once to one source.
2612+
* If mapped multiple times, only one source will play on given channel
2613+
* (sources are not mixed together).
2614+
*
2615+
* For recording, duplicate mapping is OK. We will get the same signal multiple times.
2616+
*
2617+
* Channels 7-8 are in both directions fixed to FX SEND / FX RETURN.
2618+
*
2619+
* See also notes in the quirks-table.h file.
2620+
*/
2621+
2622+
struct snd_pioneer_djm_option {
2623+
const u16 wIndex;
2624+
const u16 wValue;
2625+
const char *name;
2626+
};
2627+
2628+
static const struct snd_pioneer_djm_option snd_pioneer_djm_options_capture_level[] = {
2629+
{ .name = "-5 dB", .wValue = 0x0300, .wIndex = 0x8003 },
2630+
{ .name = "-10 dB", .wValue = 0x0200, .wIndex = 0x8003 },
2631+
{ .name = "-15 dB", .wValue = 0x0100, .wIndex = 0x8003 },
2632+
{ .name = "-19 dB", .wValue = 0x0000, .wIndex = 0x8003 }
2633+
};
2634+
2635+
static const struct snd_pioneer_djm_option snd_pioneer_djm_options_capture_ch12[] = {
2636+
{ .name = "CH1 Control Tone PHONO", .wValue = 0x0103, .wIndex = 0x8002 },
2637+
{ .name = "CH1 Control Tone LINE", .wValue = 0x0100, .wIndex = 0x8002 },
2638+
{ .name = "Post CH1 Fader", .wValue = 0x0106, .wIndex = 0x8002 },
2639+
{ .name = "Cross Fader A", .wValue = 0x0107, .wIndex = 0x8002 },
2640+
{ .name = "Cross Fader B", .wValue = 0x0108, .wIndex = 0x8002 },
2641+
{ .name = "MIC", .wValue = 0x0109, .wIndex = 0x8002 },
2642+
{ .name = "AUX", .wValue = 0x010d, .wIndex = 0x8002 },
2643+
{ .name = "REC OUT", .wValue = 0x010a, .wIndex = 0x8002 }
2644+
};
2645+
2646+
static const struct snd_pioneer_djm_option snd_pioneer_djm_options_capture_ch34[] = {
2647+
{ .name = "CH2 Control Tone PHONO", .wValue = 0x0203, .wIndex = 0x8002 },
2648+
{ .name = "CH2 Control Tone LINE", .wValue = 0x0200, .wIndex = 0x8002 },
2649+
{ .name = "Post CH2 Fader", .wValue = 0x0206, .wIndex = 0x8002 },
2650+
{ .name = "Cross Fader A", .wValue = 0x0207, .wIndex = 0x8002 },
2651+
{ .name = "Cross Fader B", .wValue = 0x0208, .wIndex = 0x8002 },
2652+
{ .name = "MIC", .wValue = 0x0209, .wIndex = 0x8002 },
2653+
{ .name = "AUX", .wValue = 0x020d, .wIndex = 0x8002 },
2654+
{ .name = "REC OUT", .wValue = 0x020a, .wIndex = 0x8002 }
2655+
};
2656+
2657+
static const struct snd_pioneer_djm_option snd_pioneer_djm_options_capture_ch56[] = {
2658+
{ .name = "REC OUT", .wValue = 0x030a, .wIndex = 0x8002 },
2659+
{ .name = "Post CH1 Fader", .wValue = 0x0311, .wIndex = 0x8002 },
2660+
{ .name = "Post CH2 Fader", .wValue = 0x0312, .wIndex = 0x8002 },
2661+
{ .name = "Cross Fader A", .wValue = 0x0307, .wIndex = 0x8002 },
2662+
{ .name = "Cross Fader B", .wValue = 0x0308, .wIndex = 0x8002 },
2663+
{ .name = "MIC", .wValue = 0x0309, .wIndex = 0x8002 },
2664+
{ .name = "AUX", .wValue = 0x030d, .wIndex = 0x8002 }
2665+
};
2666+
2667+
static const struct snd_pioneer_djm_option snd_pioneer_djm_options_playback_12[] = {
2668+
{ .name = "CH1", .wValue = 0x0100, .wIndex = 0x8016 },
2669+
{ .name = "CH2", .wValue = 0x0101, .wIndex = 0x8016 },
2670+
{ .name = "AUX", .wValue = 0x0104, .wIndex = 0x8016 }
2671+
};
2672+
2673+
static const struct snd_pioneer_djm_option snd_pioneer_djm_options_playback_34[] = {
2674+
{ .name = "CH1", .wValue = 0x0200, .wIndex = 0x8016 },
2675+
{ .name = "CH2", .wValue = 0x0201, .wIndex = 0x8016 },
2676+
{ .name = "AUX", .wValue = 0x0204, .wIndex = 0x8016 }
2677+
};
2678+
2679+
static const struct snd_pioneer_djm_option snd_pioneer_djm_options_playback_56[] = {
2680+
{ .name = "CH1", .wValue = 0x0300, .wIndex = 0x8016 },
2681+
{ .name = "CH2", .wValue = 0x0301, .wIndex = 0x8016 },
2682+
{ .name = "AUX", .wValue = 0x0304, .wIndex = 0x8016 }
2683+
};
2684+
2685+
struct snd_pioneer_djm_option_group {
2686+
const char *name;
2687+
const struct snd_pioneer_djm_option *options;
2688+
const size_t count;
2689+
const u16 default_value;
2690+
};
2691+
2692+
#define snd_pioneer_djm_option_group_item(_name, suffix, _default_value) { \
2693+
.name = _name, \
2694+
.options = snd_pioneer_djm_options_##suffix, \
2695+
.count = ARRAY_SIZE(snd_pioneer_djm_options_##suffix), \
2696+
.default_value = _default_value }
2697+
2698+
static const struct snd_pioneer_djm_option_group snd_pioneer_djm_option_groups[] = {
2699+
snd_pioneer_djm_option_group_item("Master Capture Level Capture Switch", capture_level, 0),
2700+
snd_pioneer_djm_option_group_item("Capture 1-2 Capture Switch", capture_ch12, 2),
2701+
snd_pioneer_djm_option_group_item("Capture 3-4 Capture Switch", capture_ch34, 2),
2702+
snd_pioneer_djm_option_group_item("Capture 5-6 Capture Switch", capture_ch56, 0),
2703+
snd_pioneer_djm_option_group_item("Playback 1-2 Playback Switch", playback_12, 0),
2704+
snd_pioneer_djm_option_group_item("Playback 3-4 Playback Switch", playback_34, 1),
2705+
snd_pioneer_djm_option_group_item("Playback 5-6 Playback Switch", playback_56, 2)
2706+
};
2707+
2708+
// layout of the kcontrol->private_value:
2709+
#define SND_PIONEER_DJM_VALUE_MASK 0x0000ffff
2710+
#define SND_PIONEER_DJM_GROUP_MASK 0xffff0000
2711+
#define SND_PIONEER_DJM_GROUP_SHIFT 16
2712+
2713+
static int snd_pioneer_djm_controls_info(struct snd_kcontrol *kctl, struct snd_ctl_elem_info *info)
2714+
{
2715+
u16 group_index = kctl->private_value >> SND_PIONEER_DJM_GROUP_SHIFT;
2716+
size_t count;
2717+
const char *name;
2718+
const struct snd_pioneer_djm_option_group *group;
2719+
2720+
if (group_index >= ARRAY_SIZE(snd_pioneer_djm_option_groups))
2721+
return -EINVAL;
2722+
2723+
group = &snd_pioneer_djm_option_groups[group_index];
2724+
count = group->count;
2725+
if (info->value.enumerated.item >= count)
2726+
info->value.enumerated.item = count - 1;
2727+
name = group->options[info->value.enumerated.item].name;
2728+
strlcpy(info->value.enumerated.name, name, sizeof(info->value.enumerated.name));
2729+
info->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
2730+
info->count = 1;
2731+
info->value.enumerated.items = count;
2732+
return 0;
2733+
}
2734+
2735+
static int snd_pioneer_djm_controls_update(struct usb_mixer_interface *mixer, u16 group, u16 value)
2736+
{
2737+
int err;
2738+
2739+
if (group >= ARRAY_SIZE(snd_pioneer_djm_option_groups)
2740+
|| value >= snd_pioneer_djm_option_groups[group].count)
2741+
return -EINVAL;
2742+
2743+
err = snd_usb_lock_shutdown(mixer->chip);
2744+
if (err)
2745+
return err;
2746+
2747+
err = snd_usb_ctl_msg(
2748+
mixer->chip->dev, usb_sndctrlpipe(mixer->chip->dev, 0),
2749+
USB_REQ_SET_FEATURE,
2750+
USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
2751+
snd_pioneer_djm_option_groups[group].options[value].wValue,
2752+
snd_pioneer_djm_option_groups[group].options[value].wIndex,
2753+
NULL, 0);
2754+
2755+
snd_usb_unlock_shutdown(mixer->chip);
2756+
return err;
2757+
}
2758+
2759+
static int snd_pioneer_djm_controls_get(struct snd_kcontrol *kctl, struct snd_ctl_elem_value *elem)
2760+
{
2761+
elem->value.enumerated.item[0] = kctl->private_value & SND_PIONEER_DJM_VALUE_MASK;
2762+
return 0;
2763+
}
2764+
2765+
static int snd_pioneer_djm_controls_put(struct snd_kcontrol *kctl, struct snd_ctl_elem_value *elem)
2766+
{
2767+
struct usb_mixer_elem_list *list = snd_kcontrol_chip(kctl);
2768+
struct usb_mixer_interface *mixer = list->mixer;
2769+
unsigned long private_value = kctl->private_value;
2770+
u16 group = (private_value & SND_PIONEER_DJM_GROUP_MASK) >> SND_PIONEER_DJM_GROUP_SHIFT;
2771+
u16 value = elem->value.enumerated.item[0];
2772+
2773+
kctl->private_value = (group << SND_PIONEER_DJM_GROUP_SHIFT) | value;
2774+
2775+
return snd_pioneer_djm_controls_update(mixer, group, value);
2776+
}
2777+
2778+
static int snd_pioneer_djm_controls_resume(struct usb_mixer_elem_list *list)
2779+
{
2780+
unsigned long private_value = list->kctl->private_value;
2781+
u16 group = (private_value & SND_PIONEER_DJM_GROUP_MASK) >> SND_PIONEER_DJM_GROUP_SHIFT;
2782+
u16 value = (private_value & SND_PIONEER_DJM_VALUE_MASK);
2783+
2784+
return snd_pioneer_djm_controls_update(list->mixer, group, value);
2785+
}
2786+
2787+
static int snd_pioneer_djm_controls_create(struct usb_mixer_interface *mixer)
2788+
{
2789+
int err, i;
2790+
const struct snd_pioneer_djm_option_group *group;
2791+
struct snd_kcontrol_new knew = {
2792+
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
2793+
.access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
2794+
.index = 0,
2795+
.info = snd_pioneer_djm_controls_info,
2796+
.get = snd_pioneer_djm_controls_get,
2797+
.put = snd_pioneer_djm_controls_put
2798+
};
2799+
2800+
for (i = 0; i < ARRAY_SIZE(snd_pioneer_djm_option_groups); i++) {
2801+
group = &snd_pioneer_djm_option_groups[i];
2802+
knew.name = group->name;
2803+
knew.private_value = (i << SND_PIONEER_DJM_GROUP_SHIFT) | group->default_value;
2804+
err = snd_pioneer_djm_controls_update(mixer, i, group->default_value);
2805+
if (err)
2806+
return err;
2807+
err = add_single_ctl_with_resume(mixer, 0, snd_pioneer_djm_controls_resume,
2808+
&knew, NULL);
2809+
if (err)
2810+
return err;
2811+
}
2812+
return 0;
2813+
}
2814+
26052815
int snd_usb_mixer_apply_create_quirk(struct usb_mixer_interface *mixer)
26062816
{
26072817
int err = 0;
@@ -2706,6 +2916,9 @@ int snd_usb_mixer_apply_create_quirk(struct usb_mixer_interface *mixer)
27062916
case USB_ID(0x2a39, 0x3fb0): /* RME Babyface Pro FS */
27072917
err = snd_bbfpro_controls_create(mixer);
27082918
break;
2919+
case USB_ID(0x2b73, 0x0017): /* Pioneer DJ DJM-250MK2 */
2920+
err = snd_pioneer_djm_controls_create(mixer);
2921+
break;
27092922
}
27102923

27112924
return err;

0 commit comments

Comments
 (0)