ALSA: line6: Handle impulse response via control API

Instead of sysfs and the conditional build with Kconfig, implement the
handling of the impulse response controls via control API, and always
enable the build.  Two new controls, "Impulse Response Volume" and
"Impulse Response Period" are added as a replacement for the former
sysfs files.

Tested-by: Chris Rorvick <chris@rorvick.com>
Signed-off-by: Takashi Iwai <tiwai@suse.de>
This commit is contained in:
Takashi Iwai 2015-01-19 14:28:25 +01:00
parent ccddbe4a99
commit 075587b723
5 changed files with 76 additions and 125 deletions

View File

@ -38,15 +38,3 @@ config SND_USB_VARIAX
help
This is a driver for Variax Workbench device.
config LINE6_USB_IMPULSE_RESPONSE
bool "measure impulse response"
depends on SND_USB_LINE6
help
Say Y here to add code to measure the impulse response of a Line6
device. This is more accurate than user-space methods since it
bypasses any PCM data buffering (e.g., by ALSA or jack). This is
useful for assessing the performance of new devices, but is not
required for normal operation.
If unsure, say N.

View File

@ -244,9 +244,7 @@ static void audio_in_callback(struct urb *urb)
line6pcm->prev_fbuf = fbuf;
line6pcm->prev_fsize = fsize;
#ifdef CONFIG_LINE6_USB_IMPULSE_RESPONSE
if (!(line6pcm->flags & LINE6_BITS_PCM_IMPULSE))
#endif
if (test_bit(LINE6_INDEX_PCM_ALSA_CAPTURE_STREAM,
&line6pcm->flags) && (fsize > 0))
line6_capture_copy(line6pcm, fbuf, fsize);
@ -262,9 +260,7 @@ static void audio_in_callback(struct urb *urb)
if (!shutdown) {
submit_audio_in_urb(line6pcm);
#ifdef CONFIG_LINE6_USB_IMPULSE_RESPONSE
if (!(line6pcm->flags & LINE6_BITS_PCM_IMPULSE))
#endif
if (test_bit(LINE6_INDEX_PCM_ALSA_CAPTURE_STREAM,
&line6pcm->flags))
line6_capture_check_period(line6pcm, length);

View File

@ -21,80 +21,75 @@
#include "driver.h"
#include "playback.h"
#ifdef CONFIG_LINE6_USB_IMPULSE_RESPONSE
static struct snd_line6_pcm *dev2pcm(struct device *dev)
/* impulse response volume controls */
static int snd_line6_impulse_volume_info(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_info *uinfo)
{
struct usb_interface *interface = to_usb_interface(dev);
struct usb_line6 *line6 = usb_get_intfdata(interface);
struct snd_line6_pcm *line6pcm = line6->line6pcm;
return line6pcm;
uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
uinfo->count = 1;
uinfo->value.integer.min = 0;
uinfo->value.integer.max = 255;
return 0;
}
/*
"read" request on "impulse_volume" special file.
*/
static ssize_t impulse_volume_show(struct device *dev,
struct device_attribute *attr, char *buf)
static int snd_line6_impulse_volume_get(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
return sprintf(buf, "%d\n", dev2pcm(dev)->impulse_volume);
struct snd_line6_pcm *line6pcm = snd_kcontrol_chip(kcontrol);
ucontrol->value.integer.value[0] = line6pcm->impulse_volume;
return 0;
}
/*
"write" request on "impulse_volume" special file.
*/
static ssize_t impulse_volume_store(struct device *dev,
struct device_attribute *attr,
const char *buf, size_t count)
static int snd_line6_impulse_volume_put(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
struct snd_line6_pcm *line6pcm = dev2pcm(dev);
int value;
int ret;
struct snd_line6_pcm *line6pcm = snd_kcontrol_chip(kcontrol);
int value = ucontrol->value.integer.value[0];
ret = kstrtoint(buf, 10, &value);
if (ret < 0)
return ret;
if (line6pcm->impulse_volume == value)
return 0;
line6pcm->impulse_volume = value;
if (value > 0)
line6_pcm_acquire(line6pcm, LINE6_BITS_PCM_IMPULSE);
else
line6_pcm_release(line6pcm, LINE6_BITS_PCM_IMPULSE);
return count;
return 1;
}
static DEVICE_ATTR_RW(impulse_volume);
/*
"read" request on "impulse_period" special file.
*/
static ssize_t impulse_period_show(struct device *dev,
struct device_attribute *attr, char *buf)
/* impulse response period controls */
static int snd_line6_impulse_period_info(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_info *uinfo)
{
return sprintf(buf, "%d\n", dev2pcm(dev)->impulse_period);
uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
uinfo->count = 1;
uinfo->value.integer.min = 0;
uinfo->value.integer.max = 2000;
return 0;
}
/*
"write" request on "impulse_period" special file.
*/
static ssize_t impulse_period_store(struct device *dev,
struct device_attribute *attr,
const char *buf, size_t count)
static int snd_line6_impulse_period_get(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
int value;
int ret;
struct snd_line6_pcm *line6pcm = snd_kcontrol_chip(kcontrol);
ret = kstrtoint(buf, 10, &value);
if (ret < 0)
return ret;
dev2pcm(dev)->impulse_period = value;
return count;
ucontrol->value.integer.value[0] = line6pcm->impulse_period;
return 0;
}
static DEVICE_ATTR_RW(impulse_period);
#endif
static int snd_line6_impulse_period_put(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
struct snd_line6_pcm *line6pcm = snd_kcontrol_chip(kcontrol);
int value = ucontrol->value.integer.value[0];
if (line6pcm->impulse_period == value)
return 0;
line6pcm->impulse_period = value;
return 1;
}
static bool test_flags(unsigned long flags0, unsigned long flags1,
unsigned long mask)
@ -314,14 +309,28 @@ static int snd_line6_control_playback_put(struct snd_kcontrol *kcontrol,
}
/* control definition */
static struct snd_kcontrol_new line6_control_playback = {
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
.name = "PCM Playback Volume",
.index = 0,
.access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
.info = snd_line6_control_playback_info,
.get = snd_line6_control_playback_get,
.put = snd_line6_control_playback_put
static struct snd_kcontrol_new line6_controls[] = {
{
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
.name = "PCM Playback Volume",
.info = snd_line6_control_playback_info,
.get = snd_line6_control_playback_get,
.put = snd_line6_control_playback_put
},
{
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
.name = "Impulse Response Volume",
.info = snd_line6_impulse_volume_info,
.get = snd_line6_impulse_volume_get,
.put = snd_line6_impulse_volume_put
},
{
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
.name = "Impulse Response Period",
.info = snd_line6_impulse_period_info,
.get = snd_line6_impulse_period_get,
.put = snd_line6_impulse_period_put
},
};
/*
@ -332,11 +341,6 @@ static void line6_cleanup_pcm(struct snd_pcm *pcm)
int i;
struct snd_line6_pcm *line6pcm = snd_pcm_chip(pcm);
#ifdef CONFIG_LINE6_USB_IMPULSE_RESPONSE
device_remove_file(line6pcm->line6->ifcdev, &dev_attr_impulse_volume);
device_remove_file(line6pcm->line6->ifcdev, &dev_attr_impulse_period);
#endif
for (i = LINE6_ISO_BUFFERS; i--;) {
if (line6pcm->urb_audio_out[i]) {
usb_kill_urb(line6pcm->urb_audio_out[i]);
@ -423,7 +427,7 @@ int line6_init_pcm(struct usb_line6 *line6,
.dev_free = snd_line6_pcm_free,
};
int err;
int i, err;
unsigned ep_read = line6->properties->ep_audio_r;
unsigned ep_write = line6->properties->ep_audio_w;
struct snd_line6_pcm *line6pcm;
@ -462,6 +466,7 @@ int line6_init_pcm(struct usb_line6 *line6,
spin_lock_init(&line6pcm->lock_audio_out);
spin_lock_init(&line6pcm->lock_audio_in);
spin_lock_init(&line6pcm->lock_trigger);
line6pcm->impulse_period = LINE6_IMPULSE_DEFAULT_PERIOD;
err = line6_create_audio_out_urbs(line6pcm);
if (err < 0)
@ -472,24 +477,12 @@ int line6_init_pcm(struct usb_line6 *line6,
return err;
/* mixer: */
err =
snd_ctl_add(line6->card,
snd_ctl_new1(&line6_control_playback, line6pcm));
if (err < 0)
return err;
#ifdef CONFIG_LINE6_USB_IMPULSE_RESPONSE
/* impulse response test: */
err = device_create_file(line6->ifcdev, &dev_attr_impulse_volume);
if (err < 0)
return err;
err = device_create_file(line6->ifcdev, &dev_attr_impulse_period);
if (err < 0)
return err;
line6pcm->impulse_period = LINE6_IMPULSE_DEFAULT_PERIOD;
#endif
for (i = 0; i < ARRAY_SIZE(line6_controls); i++) {
err = snd_ctl_add(line6->card,
snd_ctl_new1(&line6_controls[i], line6pcm));
if (err < 0)
return err;
}
return 0;
}

View File

@ -35,9 +35,7 @@
/* in a "full speed" device (such as the PODxt Pro) this means 1ms */
#define LINE6_ISO_INTERVAL 1
#ifdef CONFIG_LINE6_USB_IMPULSE_RESPONSE
#define LINE6_IMPULSE_DEFAULT_PERIOD 100
#endif
/*
Get substream from Line6 PCM data structure
@ -89,12 +87,10 @@ enum {
LINE6_INDEX_PCM_MONITOR_PLAYBACK_STREAM,
LINE6_INDEX_PCM_MONITOR_CAPTURE_BUFFER,
LINE6_INDEX_PCM_MONITOR_CAPTURE_STREAM,
#ifdef CONFIG_LINE6_USB_IMPULSE_RESPONSE
LINE6_INDEX_PCM_IMPULSE_PLAYBACK_BUFFER,
LINE6_INDEX_PCM_IMPULSE_PLAYBACK_STREAM,
LINE6_INDEX_PCM_IMPULSE_CAPTURE_BUFFER,
LINE6_INDEX_PCM_IMPULSE_CAPTURE_STREAM,
#endif
LINE6_INDEX_PAUSE_PLAYBACK,
LINE6_INDEX_PREPARED,
@ -109,12 +105,10 @@ enum {
LINE6_BIT(PCM_MONITOR_PLAYBACK_STREAM),
LINE6_BIT(PCM_MONITOR_CAPTURE_BUFFER),
LINE6_BIT(PCM_MONITOR_CAPTURE_STREAM),
#ifdef CONFIG_LINE6_USB_IMPULSE_RESPONSE
LINE6_BIT(PCM_IMPULSE_PLAYBACK_BUFFER),
LINE6_BIT(PCM_IMPULSE_PLAYBACK_STREAM),
LINE6_BIT(PCM_IMPULSE_CAPTURE_BUFFER),
LINE6_BIT(PCM_IMPULSE_CAPTURE_STREAM),
#endif
LINE6_BIT(PAUSE_PLAYBACK),
LINE6_BIT(PREPARED),
@ -133,40 +127,30 @@ enum {
LINE6_BIT_PCM_MONITOR_CAPTURE_BUFFER |
LINE6_BIT_PCM_MONITOR_CAPTURE_STREAM,
#ifdef CONFIG_LINE6_USB_IMPULSE_RESPONSE
LINE6_BITS_PCM_IMPULSE =
LINE6_BIT_PCM_IMPULSE_PLAYBACK_BUFFER |
LINE6_BIT_PCM_IMPULSE_PLAYBACK_STREAM |
LINE6_BIT_PCM_IMPULSE_CAPTURE_BUFFER |
LINE6_BIT_PCM_IMPULSE_CAPTURE_STREAM,
#endif
/* combined bit masks (by direction): */
LINE6_BITS_PLAYBACK_BUFFER =
#ifdef CONFIG_LINE6_USB_IMPULSE_RESPONSE
LINE6_BIT_PCM_IMPULSE_PLAYBACK_BUFFER |
#endif
LINE6_BIT_PCM_ALSA_PLAYBACK_BUFFER |
LINE6_BIT_PCM_MONITOR_PLAYBACK_BUFFER,
LINE6_BITS_PLAYBACK_STREAM =
#ifdef CONFIG_LINE6_USB_IMPULSE_RESPONSE
LINE6_BIT_PCM_IMPULSE_PLAYBACK_STREAM |
#endif
LINE6_BIT_PCM_ALSA_PLAYBACK_STREAM |
LINE6_BIT_PCM_MONITOR_PLAYBACK_STREAM,
LINE6_BITS_CAPTURE_BUFFER =
#ifdef CONFIG_LINE6_USB_IMPULSE_RESPONSE
LINE6_BIT_PCM_IMPULSE_CAPTURE_BUFFER |
#endif
LINE6_BIT_PCM_ALSA_CAPTURE_BUFFER |
LINE6_BIT_PCM_MONITOR_CAPTURE_BUFFER,
LINE6_BITS_CAPTURE_STREAM =
#ifdef CONFIG_LINE6_USB_IMPULSE_RESPONSE
LINE6_BIT_PCM_IMPULSE_CAPTURE_STREAM |
#endif
LINE6_BIT_PCM_ALSA_CAPTURE_STREAM |
LINE6_BIT_PCM_MONITOR_CAPTURE_STREAM,
@ -338,7 +322,6 @@ struct snd_line6_pcm {
*/
int volume_monitor;
#ifdef CONFIG_LINE6_USB_IMPULSE_RESPONSE
/**
Volume of impulse response test signal (if zero, test is disabled).
*/
@ -353,7 +336,6 @@ struct snd_line6_pcm {
Counter for impulse response test signal.
*/
int impulse_count;
#endif
/**
Several status bits (see LINE6_BIT_*).

View File

@ -60,8 +60,6 @@ static void change_volume(struct urb *urb_out, int volume[],
}
}
#ifdef CONFIG_LINE6_USB_IMPULSE_RESPONSE
/*
Create signal for impulse response test.
*/
@ -105,8 +103,6 @@ static void create_impulse_test_signal(struct snd_line6_pcm *line6pcm,
}
}
#endif
/*
Add signal to buffer for software monitoring.
*/
@ -243,7 +239,6 @@ static int submit_audio_out_urb(struct snd_line6_pcm *line6pcm)
change_volume(urb_out, line6pcm->volume_playback, bytes_per_frame);
if (line6pcm->prev_fbuf != NULL) {
#ifdef CONFIG_LINE6_USB_IMPULSE_RESPONSE
if (line6pcm->flags & LINE6_BITS_PCM_IMPULSE) {
create_impulse_test_signal(line6pcm, urb_out,
bytes_per_frame);
@ -257,7 +252,6 @@ static int submit_audio_out_urb(struct snd_line6_pcm *line6pcm)
urb_out->transfer_buffer_length);
}
} else {
#endif
if (!
(line6pcm->line6->
properties->capabilities & LINE6_CAP_HWMON)
@ -266,9 +260,7 @@ static int submit_audio_out_urb(struct snd_line6_pcm *line6pcm)
add_monitor_signal(urb_out, line6pcm->prev_fbuf,
line6pcm->volume_monitor,
bytes_per_frame);
#ifdef CONFIG_LINE6_USB_IMPULSE_RESPONSE
}
#endif
}
ret = usb_submit_urb(urb_out, GFP_ATOMIC);