Commit f56742cc authored by Andrej Krutak's avatar Andrej Krutak Committed by Takashi Iwai

ALSA: line6: Add LINE6_CAP_IN_NEEDS_OUT, a void playback stream during capture

E.g. POD X3 seems to require playback data to be sent to it to generate
capture data. Otherwise the device stalls and doesn't send any more capture
data until it's reset.
Signed-off-by: default avatarAndrej Krutak <dev@andree.sk>
Signed-off-by: default avatarTakashi Iwai <tiwai@suse.de>
parent 97d78acf
...@@ -232,6 +232,8 @@ static int snd_line6_capture_open(struct snd_pcm_substream *substream) ...@@ -232,6 +232,8 @@ static int snd_line6_capture_open(struct snd_pcm_substream *substream)
if (err < 0) if (err < 0)
return err; return err;
line6_pcm_acquire(line6pcm, LINE6_STREAM_CAPTURE_HELPER, false);
runtime->hw = line6pcm->properties->capture_hw; runtime->hw = line6pcm->properties->capture_hw;
return 0; return 0;
} }
...@@ -239,6 +241,9 @@ static int snd_line6_capture_open(struct snd_pcm_substream *substream) ...@@ -239,6 +241,9 @@ static int snd_line6_capture_open(struct snd_pcm_substream *substream)
/* close capture callback */ /* close capture callback */
static int snd_line6_capture_close(struct snd_pcm_substream *substream) static int snd_line6_capture_close(struct snd_pcm_substream *substream)
{ {
struct snd_line6_pcm *line6pcm = snd_pcm_substream_chip(substream);
line6_pcm_release(line6pcm, LINE6_STREAM_CAPTURE_HELPER);
return 0; return 0;
} }
......
...@@ -100,8 +100,10 @@ enum { ...@@ -100,8 +100,10 @@ enum {
LINE6_CAP_CONTROL = 1 << 0, LINE6_CAP_CONTROL = 1 << 0,
/* device supports PCM input/output via USB */ /* device supports PCM input/output via USB */
LINE6_CAP_PCM = 1 << 1, LINE6_CAP_PCM = 1 << 1,
/* device support hardware monitoring */ /* device supports hardware monitoring */
LINE6_CAP_HWMON = 1 << 2, LINE6_CAP_HWMON = 1 << 2,
/* device requires output data when input is read */
LINE6_CAP_IN_NEEDS_OUT = 1 << 3,
}; };
/* /*
......
...@@ -52,7 +52,7 @@ static int snd_line6_impulse_volume_put(struct snd_kcontrol *kcontrol, ...@@ -52,7 +52,7 @@ static int snd_line6_impulse_volume_put(struct snd_kcontrol *kcontrol,
line6pcm->impulse_volume = value; line6pcm->impulse_volume = value;
if (value > 0) { if (value > 0) {
err = line6_pcm_acquire(line6pcm, LINE6_STREAM_IMPULSE); err = line6_pcm_acquire(line6pcm, LINE6_STREAM_IMPULSE, true);
if (err < 0) { if (err < 0) {
line6pcm->impulse_volume = 0; line6pcm->impulse_volume = 0;
return err; return err;
...@@ -242,6 +242,14 @@ int snd_line6_trigger(struct snd_pcm_substream *substream, int cmd) ...@@ -242,6 +242,14 @@ int snd_line6_trigger(struct snd_pcm_substream *substream, int cmd)
switch (cmd) { switch (cmd) {
case SNDRV_PCM_TRIGGER_START: case SNDRV_PCM_TRIGGER_START:
case SNDRV_PCM_TRIGGER_RESUME: case SNDRV_PCM_TRIGGER_RESUME:
if (s->stream == SNDRV_PCM_STREAM_CAPTURE &&
(line6pcm->line6->properties->capabilities &
LINE6_CAP_IN_NEEDS_OUT)) {
err = line6_stream_start(line6pcm, SNDRV_PCM_STREAM_PLAYBACK,
LINE6_STREAM_CAPTURE_HELPER);
if (err < 0)
return err;
}
err = line6_stream_start(line6pcm, s->stream, err = line6_stream_start(line6pcm, s->stream,
LINE6_STREAM_PCM); LINE6_STREAM_PCM);
if (err < 0) if (err < 0)
...@@ -250,6 +258,12 @@ int snd_line6_trigger(struct snd_pcm_substream *substream, int cmd) ...@@ -250,6 +258,12 @@ int snd_line6_trigger(struct snd_pcm_substream *substream, int cmd)
case SNDRV_PCM_TRIGGER_STOP: case SNDRV_PCM_TRIGGER_STOP:
case SNDRV_PCM_TRIGGER_SUSPEND: case SNDRV_PCM_TRIGGER_SUSPEND:
if (s->stream == SNDRV_PCM_STREAM_CAPTURE &&
(line6pcm->line6->properties->capabilities &
LINE6_CAP_IN_NEEDS_OUT)) {
line6_stream_stop(line6pcm, SNDRV_PCM_STREAM_PLAYBACK,
LINE6_STREAM_CAPTURE_HELPER);
}
line6_stream_stop(line6pcm, s->stream, line6_stream_stop(line6pcm, s->stream,
LINE6_STREAM_PCM); LINE6_STREAM_PCM);
break; break;
...@@ -283,14 +297,15 @@ snd_pcm_uframes_t snd_line6_pointer(struct snd_pcm_substream *substream) ...@@ -283,14 +297,15 @@ snd_pcm_uframes_t snd_line6_pointer(struct snd_pcm_substream *substream)
return pstr->pos_done; return pstr->pos_done;
} }
/* Acquire and start duplex streams: /* Acquire and optionally start duplex streams:
* type is either LINE6_STREAM_IMPULSE or LINE6_STREAM_MONITOR * type is either LINE6_STREAM_IMPULSE or LINE6_STREAM_MONITOR
*/ */
int line6_pcm_acquire(struct snd_line6_pcm *line6pcm, int type) int line6_pcm_acquire(struct snd_line6_pcm *line6pcm, int type, bool start)
{ {
struct line6_pcm_stream *pstr; struct line6_pcm_stream *pstr;
int ret = 0, dir; int ret = 0, dir;
/* TODO: We should assert SNDRV_PCM_STREAM_PLAYBACK/CAPTURE == 0/1 */
mutex_lock(&line6pcm->state_mutex); mutex_lock(&line6pcm->state_mutex);
for (dir = 0; dir < 2; dir++) { for (dir = 0; dir < 2; dir++) {
pstr = get_stream(line6pcm, dir); pstr = get_stream(line6pcm, dir);
...@@ -300,10 +315,12 @@ int line6_pcm_acquire(struct snd_line6_pcm *line6pcm, int type) ...@@ -300,10 +315,12 @@ int line6_pcm_acquire(struct snd_line6_pcm *line6pcm, int type)
if (!pstr->running) if (!pstr->running)
line6_wait_clear_audio_urbs(line6pcm, pstr); line6_wait_clear_audio_urbs(line6pcm, pstr);
} }
for (dir = 0; dir < 2; dir++) { if (start) {
ret = line6_stream_start(line6pcm, dir, type); for (dir = 0; dir < 2; dir++) {
if (ret < 0) ret = line6_stream_start(line6pcm, dir, type);
goto error; if (ret < 0)
goto error;
}
} }
error: error:
mutex_unlock(&line6pcm->state_mutex); mutex_unlock(&line6pcm->state_mutex);
......
...@@ -73,6 +73,7 @@ enum { ...@@ -73,6 +73,7 @@ enum {
LINE6_STREAM_PCM, LINE6_STREAM_PCM,
LINE6_STREAM_MONITOR, LINE6_STREAM_MONITOR,
LINE6_STREAM_IMPULSE, LINE6_STREAM_IMPULSE,
LINE6_STREAM_CAPTURE_HELPER,
}; };
/* misc bit flags for PCM operation */ /* misc bit flags for PCM operation */
...@@ -191,7 +192,8 @@ extern int snd_line6_hw_params(struct snd_pcm_substream *substream, ...@@ -191,7 +192,8 @@ extern int snd_line6_hw_params(struct snd_pcm_substream *substream,
extern int snd_line6_hw_free(struct snd_pcm_substream *substream); extern int snd_line6_hw_free(struct snd_pcm_substream *substream);
extern snd_pcm_uframes_t snd_line6_pointer(struct snd_pcm_substream *substream); extern snd_pcm_uframes_t snd_line6_pointer(struct snd_pcm_substream *substream);
extern void line6_pcm_disconnect(struct snd_line6_pcm *line6pcm); extern void line6_pcm_disconnect(struct snd_line6_pcm *line6pcm);
extern int line6_pcm_acquire(struct snd_line6_pcm *line6pcm, int type); extern int line6_pcm_acquire(struct snd_line6_pcm *line6pcm, int type,
bool start);
extern void line6_pcm_release(struct snd_line6_pcm *line6pcm, int type); extern void line6_pcm_release(struct snd_line6_pcm *line6pcm, int type);
#endif #endif
...@@ -177,7 +177,7 @@ static int snd_toneport_monitor_put(struct snd_kcontrol *kcontrol, ...@@ -177,7 +177,7 @@ static int snd_toneport_monitor_put(struct snd_kcontrol *kcontrol,
line6pcm->volume_monitor = ucontrol->value.integer.value[0]; line6pcm->volume_monitor = ucontrol->value.integer.value[0];
if (line6pcm->volume_monitor > 0) { if (line6pcm->volume_monitor > 0) {
err = line6_pcm_acquire(line6pcm, LINE6_STREAM_MONITOR); err = line6_pcm_acquire(line6pcm, LINE6_STREAM_MONITOR, true);
if (err < 0) { if (err < 0) {
line6pcm->volume_monitor = 0; line6pcm->volume_monitor = 0;
line6_pcm_release(line6pcm, LINE6_STREAM_MONITOR); line6_pcm_release(line6pcm, LINE6_STREAM_MONITOR);
...@@ -246,7 +246,7 @@ static void toneport_start_pcm(unsigned long arg) ...@@ -246,7 +246,7 @@ static void toneport_start_pcm(unsigned long arg)
struct usb_line6_toneport *toneport = (struct usb_line6_toneport *)arg; struct usb_line6_toneport *toneport = (struct usb_line6_toneport *)arg;
struct usb_line6 *line6 = &toneport->line6; struct usb_line6 *line6 = &toneport->line6;
line6_pcm_acquire(line6->line6pcm, LINE6_STREAM_MONITOR); line6_pcm_acquire(line6->line6pcm, LINE6_STREAM_MONITOR, true);
} }
/* control definition */ /* control definition */
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment