Skip to content

Commit

Permalink
ALSA: usb-audio: Support changing input on Sound Blaster E1
Browse files Browse the repository at this point in the history
The E1 has two headphone jacks, one of which can be set as a microphone
input. In the default mode, it uses the built-in microphone as an input.
By sending a special command, the second headphone jack is instead used
as an input.

This might work with the E3 as well, but I don't have one of those to
test it.

Signed-off-by: Ian Douglas Scott <ian@iandouglasscott.com>
Signed-off-by: Takashi Iwai <tiwai@suse.de>
  • Loading branch information
ids1024 authored and tiwai committed Jan 18, 2018
1 parent 1b6832b commit 388fdb8
Showing 1 changed file with 82 additions and 0 deletions.
82 changes: 82 additions & 0 deletions sound/usb/mixer_quirks.c
Expand Up @@ -27,6 +27,7 @@
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/

#include <linux/hid.h>
#include <linux/init.h>
#include <linux/slab.h>
#include <linux/usb.h>
Expand Down Expand Up @@ -1721,6 +1722,83 @@ static int snd_microii_controls_create(struct usb_mixer_interface *mixer)
return 0;
}

/* Creative Sound Blaster E1 */

static int snd_soundblaster_e1_switch_get(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
ucontrol->value.integer.value[0] = kcontrol->private_value;
return 0;
}

static int snd_soundblaster_e1_switch_update(struct usb_mixer_interface *mixer,
unsigned char state)
{
struct snd_usb_audio *chip = mixer->chip;
int err;
unsigned char buff[2];

buff[0] = 0x02;
buff[1] = state ? 0x02 : 0x00;

err = snd_usb_lock_shutdown(chip);
if (err < 0)
return err;
err = snd_usb_ctl_msg(chip->dev,
usb_sndctrlpipe(chip->dev, 0), HID_REQ_SET_REPORT,
USB_TYPE_CLASS | USB_RECIP_INTERFACE | USB_DIR_OUT,
0x0202, 3, buff, 2);
snd_usb_unlock_shutdown(chip);
return err;
}

static int snd_soundblaster_e1_switch_put(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
struct usb_mixer_elem_list *list = snd_kcontrol_chip(kcontrol);
unsigned char value = !!ucontrol->value.integer.value[0];
int err;

if (kcontrol->private_value == value)
return 0;
kcontrol->private_value = value;
err = snd_soundblaster_e1_switch_update(list->mixer, value);
return err < 0 ? err : 1;
}

static int snd_soundblaster_e1_switch_resume(struct usb_mixer_elem_list *list)
{
return snd_soundblaster_e1_switch_update(list->mixer,
list->kctl->private_value);
}

static int snd_soundblaster_e1_switch_info(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_info *uinfo)
{
static const char *const texts[2] = {
"Mic", "Aux"
};

return snd_ctl_enum_info(uinfo, 1, ARRAY_SIZE(texts), texts);
}

static struct snd_kcontrol_new snd_soundblaster_e1_input_switch = {
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
.name = "Input Source",
.info = snd_soundblaster_e1_switch_info,
.get = snd_soundblaster_e1_switch_get,
.put = snd_soundblaster_e1_switch_put,
.private_value = 0,
};

static int snd_soundblaster_e1_switch_create(struct usb_mixer_interface *mixer)
{
return add_single_ctl_with_resume(mixer, 0,
snd_soundblaster_e1_switch_resume,
&snd_soundblaster_e1_input_switch,
NULL);
}

int snd_usb_mixer_apply_create_quirk(struct usb_mixer_interface *mixer)
{
int err = 0;
Expand Down Expand Up @@ -1802,6 +1880,10 @@ int snd_usb_mixer_apply_create_quirk(struct usb_mixer_interface *mixer)
case USB_ID(0x1235, 0x800c): /* Focusrite Scarlett 18i20 */
err = snd_scarlett_controls_create(mixer);
break;

case USB_ID(0x041e, 0x323b): /* Creative Sound Blaster E1 */
err = snd_soundblaster_e1_switch_create(mixer);
break;
}

return err;
Expand Down

1 comment on commit 388fdb8

@APCodeRepo
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Unless I am missing something obvious, what is the special command that can be sent?

Please sign in to comment.