[alsa-devel] [PATCH 3/3] snd-bcd2000: add control interface
Mario Kicherer
dev at kicherer.org
Sat Jan 31 22:34:25 CET 2015
Signed-off-by: Mario Kicherer <dev at kicherer.org>
---
sound/usb/bcd2000/Makefile | 2 +-
sound/usb/bcd2000/bcd2000.c | 6 +++
sound/usb/bcd2000/bcd2000.h | 2 +
sound/usb/bcd2000/control.c | 119 ++++++++++++++++++++++++++++++++++++++++++++
sound/usb/bcd2000/control.h | 15 ++++++
5 files changed, 143 insertions(+), 1 deletion(-)
create mode 100644 sound/usb/bcd2000/control.c
create mode 100644 sound/usb/bcd2000/control.h
diff --git a/sound/usb/bcd2000/Makefile b/sound/usb/bcd2000/Makefile
index d424dff..176324f 100644
--- a/sound/usb/bcd2000/Makefile
+++ b/sound/usb/bcd2000/Makefile
@@ -1,3 +1,3 @@
-snd-bcd2000-y := bcd2000.o audio.o midi.o
+snd-bcd2000-y := bcd2000.o audio.o control.o midi.o
obj-$(CONFIG_SND_BCD2000) += snd-bcd2000.o
\ No newline at end of file
diff --git a/sound/usb/bcd2000/bcd2000.c b/sound/usb/bcd2000/bcd2000.c
index f7ba9ad..1bd5111 100644
--- a/sound/usb/bcd2000/bcd2000.c
+++ b/sound/usb/bcd2000/bcd2000.c
@@ -59,6 +59,8 @@ static void bcd2000_disconnect(struct usb_interface *interface)
/* make sure that userspace cannot create new requests */
snd_card_disconnect(bcd2k->card);
+ bcd2000_free_control(bcd2k);
+
bcd2000_free_audio(bcd2k);
bcd2000_free_midi(bcd2k);
@@ -126,6 +128,10 @@ static int bcd2000_probe(struct usb_interface *interface,
if (err < 0)
goto probe_error;
+ err = bcd2000_init_control(bcd2k);
+ if (err < 0)
+ goto probe_error;
+
err = snd_card_register(card);
if (err < 0)
goto probe_error;
diff --git a/sound/usb/bcd2000/bcd2000.h b/sound/usb/bcd2000/bcd2000.h
index 802685b..96d93f5 100644
--- a/sound/usb/bcd2000/bcd2000.h
+++ b/sound/usb/bcd2000/bcd2000.h
@@ -10,6 +10,7 @@
#define PREFIX "snd-bcd2000: "
#include "audio.h"
+#include "control.h"
#include "midi.h"
struct bcd2000 {
@@ -18,6 +19,7 @@ struct bcd2000 {
struct usb_interface *intf;
int card_index;
+ struct bcd2000_control control;
struct bcd2000_midi midi;
struct bcd2000_pcm pcm;
};
diff --git a/sound/usb/bcd2000/control.c b/sound/usb/bcd2000/control.c
new file mode 100644
index 0000000..70b3620
--- /dev/null
+++ b/sound/usb/bcd2000/control.c
@@ -0,0 +1,119 @@
+/*
+ * Behringer BCD2000 driver
+ *
+ * Copyright (C) 2014 Mario Kicherer (dev at kicherer.org)
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/slab.h>
+#include <linux/interrupt.h>
+#include <sound/control.h>
+#include <sound/tlv.h>
+
+#include "bcd2000.h"
+#include "control.h"
+#include "midi.h"
+
+static const char * const phono_mic_sw_texts[2] = { "Phono A", "Mic" };
+
+/*
+ * switch between Phono A and Mic input using a MIDI program change command
+ *
+ * The manual specifies "c0 [00|01]" but the windows driver sends
+ * "09 01 [00|01]", we follow the manual here.
+ */
+static void bcd2000_control_phono_mic_sw_update(struct bcd2000_control *ctrl)
+{
+ int actual_length, ret;
+ char buffer[MIDI_URB_BUFSIZE] = MIDI_CMD_PREFIX_INIT;
+
+ buffer[2] = 2;
+ buffer[3] = 0xC0;
+ buffer[4] = ctrl->phono_mic_switch;
+
+ ret = usb_interrupt_msg(ctrl->bcd2k->dev,
+ usb_sndintpipe(ctrl->bcd2k->dev, 0x1),
+ buffer, MIDI_URB_BUFSIZE, &actual_length, 100);
+ if (ret)
+ dev_err(&ctrl->bcd2k->dev->dev, PREFIX
+ "usb_interrupt_msg failed\n");
+}
+
+static int bcd2000_control_phono_mic_sw_info(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_info *uinfo)
+{
+ return snd_ctl_enum_info(uinfo, 1, 2, phono_mic_sw_texts);
+}
+
+static int bcd2000_control_phono_mic_sw_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct bcd2000_control *ctrl = snd_kcontrol_chip(kcontrol);
+ int changed = 0;
+
+ if (ctrl->phono_mic_switch != ucontrol->value.enumerated.item[0]) {
+ ctrl->phono_mic_switch = ucontrol->value.enumerated.item[0];
+
+ bcd2000_control_phono_mic_sw_update(ctrl);
+
+ changed = 1;
+ }
+
+ return changed;
+}
+
+static int bcd2000_control_phono_mic_sw_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct bcd2000_control *ctrl = snd_kcontrol_chip(kcontrol);
+
+ ucontrol->value.enumerated.item[0] = ctrl->phono_mic_switch;
+
+ return 0;
+}
+
+static struct snd_kcontrol_new elements[] = {
+ {
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+ .name = "Phono A / Mic Capture Switch",
+ .index = 0,
+ .access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
+ .info = bcd2000_control_phono_mic_sw_info,
+ .get = bcd2000_control_phono_mic_sw_get,
+ .put = bcd2000_control_phono_mic_sw_put
+ },
+ {}
+};
+
+int bcd2000_init_control(struct bcd2000 *bcd2k)
+{
+ int i, ret;
+
+ bcd2k->control.bcd2k = bcd2k;
+
+ i = 0;
+ while (elements[i].name) {
+ ret = snd_ctl_add(bcd2k->card, snd_ctl_new1(&elements[i],
+ &bcd2k->control));
+ if (ret < 0) {
+ dev_err(&bcd2k->dev->dev, "cannot add control\n");
+ return ret;
+ }
+ i++;
+ }
+
+ return 0;
+}
+
+void bcd2000_free_control(struct bcd2000 *bcd2k)
+{
+}
diff --git a/sound/usb/bcd2000/control.h b/sound/usb/bcd2000/control.h
new file mode 100644
index 0000000..79cc053
--- /dev/null
+++ b/sound/usb/bcd2000/control.h
@@ -0,0 +1,15 @@
+#ifndef CONTROL_H
+#define CONTROL_H
+
+struct bcd2000;
+
+struct bcd2000_control {
+ struct bcd2000 *bcd2k;
+
+ bool phono_mic_switch;
+};
+
+int bcd2000_init_control(struct bcd2000 *bcd2k);
+void bcd2000_free_control(struct bcd2000 *bcd2k);
+
+#endif
--
2.0.5
More information about the Alsa-devel
mailing list