Commit d8131e67 authored by Takashi Iwai's avatar Takashi Iwai
Browse files

ALSA: line6: Consolidate URB unlink and sync helpers



The codes to unlink and sync URBs are identical for both playback and
capture streams.  Consolidate to single helper functions.

Tested-by: default avatarChris Rorvick <chris@rorvick.com>
Signed-off-by: default avatarTakashi Iwai <tiwai@suse.de>
parent ad0119ab
Loading
Loading
Loading
Loading
+0 −52
Original line number Diff line number Diff line
@@ -84,58 +84,6 @@ int line6_submit_audio_in_all_urbs(struct snd_line6_pcm *line6pcm)
	return 0;
}

/*
	Unlink all currently active capture URBs.
*/
void line6_unlink_audio_in_urbs(struct snd_line6_pcm *line6pcm)
{
	unsigned int i;

	for (i = 0; i < LINE6_ISO_BUFFERS; i++) {
		if (test_bit(i, &line6pcm->in.active_urbs)) {
			if (!test_and_set_bit(i, &line6pcm->in.unlink_urbs)) {
				struct urb *u = line6pcm->in.urbs[i];

				usb_unlink_urb(u);
			}
		}
	}
}

/*
	Wait until unlinking of all currently active capture URBs has been
	finished.
*/
void line6_wait_clear_audio_in_urbs(struct snd_line6_pcm *line6pcm)
{
	int timeout = HZ;
	unsigned int i;
	int alive;

	do {
		alive = 0;
		for (i = 0; i < LINE6_ISO_BUFFERS; i++) {
			if (test_bit(i, &line6pcm->in.active_urbs))
				alive++;
		}
		if (!alive)
			break;
		set_current_state(TASK_UNINTERRUPTIBLE);
		schedule_timeout(1);
	} while (--timeout > 0);
	if (alive)
		snd_printk(KERN_ERR "timeout: still %d active urbs..\n", alive);
}

/*
	Unlink all currently active capture URBs, and wait for finishing.
*/
void line6_unlink_wait_clear_audio_in_urbs(struct snd_line6_pcm *line6pcm)
{
	line6_unlink_audio_in_urbs(line6pcm);
	line6_wait_clear_audio_in_urbs(line6pcm);
}

/*
	Copy data into ALSA capture buffer.
*/
+0 −4
Original line number Diff line number Diff line
@@ -26,10 +26,6 @@ extern void line6_capture_check_period(struct snd_line6_pcm *line6pcm,
extern int line6_create_audio_in_urbs(struct snd_line6_pcm *line6pcm);
extern void line6_free_capture_buffer(struct snd_line6_pcm *line6pcm);
extern int line6_submit_audio_in_all_urbs(struct snd_line6_pcm *line6pcm);
extern void line6_unlink_audio_in_urbs(struct snd_line6_pcm *line6pcm);
extern void line6_unlink_wait_clear_audio_in_urbs(struct snd_line6_pcm
						  *line6pcm);
extern void line6_wait_clear_audio_in_urbs(struct snd_line6_pcm *line6pcm);
extern int snd_line6_capture_trigger(struct snd_line6_pcm *line6pcm, int cmd);

#endif
+69 −21
Original line number Diff line number Diff line
@@ -90,6 +90,47 @@ static int snd_line6_impulse_period_put(struct snd_kcontrol *kcontrol,
	return 1;
}

/*
	Unlink all currently active URBs.
*/
static void line6_unlink_audio_urbs(struct snd_line6_pcm *line6pcm,
				    struct line6_pcm_stream *pcms)
{
	int i;

	for (i = 0; i < LINE6_ISO_BUFFERS; i++) {
		if (test_bit(i, &pcms->active_urbs)) {
			if (!test_and_set_bit(i, &pcms->unlink_urbs))
				usb_unlink_urb(pcms->urbs[i]);
		}
	}
}

/*
	Wait until unlinking of all currently active URBs has been finished.
*/
static void line6_wait_clear_audio_urbs(struct snd_line6_pcm *line6pcm,
					struct line6_pcm_stream *pcms)
{
	int timeout = HZ;
	int i;
	int alive;

	do {
		alive = 0;
		for (i = 0; i < LINE6_ISO_BUFFERS; i++) {
			if (test_bit(i, &pcms->active_urbs))
				alive++;
		}
		if (!alive)
			break;
		set_current_state(TASK_UNINTERRUPTIBLE);
		schedule_timeout(1);
	} while (--timeout > 0);
	if (alive)
		snd_printk(KERN_ERR "timeout: still %d active urbs..\n", alive);
}

static bool test_flags(unsigned long flags0, unsigned long flags1,
		       unsigned long mask)
{
@@ -202,18 +243,18 @@ int line6_pcm_release(struct snd_line6_pcm *line6pcm, int channels)
	} while (cmpxchg(&line6pcm->flags, flags_old, flags_new) != flags_old);

	if (test_flags(flags_new, flags_old, LINE6_BITS_CAPTURE_STREAM))
		line6_unlink_audio_in_urbs(line6pcm);
		line6_unlink_audio_urbs(line6pcm, &line6pcm->in);

	if (test_flags(flags_new, flags_old, LINE6_BITS_CAPTURE_BUFFER)) {
		line6_wait_clear_audio_in_urbs(line6pcm);
		line6_wait_clear_audio_urbs(line6pcm, &line6pcm->in);
		line6_free_capture_buffer(line6pcm);
	}

	if (test_flags(flags_new, flags_old, LINE6_BITS_PLAYBACK_STREAM))
		line6_unlink_audio_out_urbs(line6pcm);
		line6_unlink_audio_urbs(line6pcm, &line6pcm->out);

	if (test_flags(flags_new, flags_old, LINE6_BITS_PLAYBACK_BUFFER)) {
		line6_wait_clear_audio_out_urbs(line6pcm);
		line6_wait_clear_audio_urbs(line6pcm, &line6pcm->out);
		line6_free_playback_buffer(line6pcm);
	}

@@ -325,21 +366,24 @@ static struct snd_kcontrol_new line6_controls[] = {
/*
	Cleanup the PCM device.
*/
static void line6_cleanup_pcm(struct snd_pcm *pcm)
static void cleanup_urbs(struct line6_pcm_stream *pcms)
{
	int i;
	struct snd_line6_pcm *line6pcm = snd_pcm_chip(pcm);

	for (i = 0; i < LINE6_ISO_BUFFERS; i++) {
		if (line6pcm->out.urbs[i]) {
			usb_kill_urb(line6pcm->out.urbs[i]);
			usb_free_urb(line6pcm->out.urbs[i]);
		if (pcms->urbs[i]) {
			usb_kill_urb(pcms->urbs[i]);
			usb_free_urb(pcms->urbs[i]);
		}
		if (line6pcm->in.urbs[i]) {
			usb_kill_urb(line6pcm->in.urbs[i]);
			usb_free_urb(line6pcm->in.urbs[i]);
	}
}

static void line6_cleanup_pcm(struct snd_pcm *pcm)
{
	struct snd_line6_pcm *line6pcm = snd_pcm_chip(pcm);

	cleanup_urbs(&line6pcm->out);
	cleanup_urbs(&line6pcm->in);
	kfree(line6pcm);
}

@@ -374,8 +418,10 @@ static int snd_line6_new_pcm(struct usb_line6 *line6, struct snd_pcm **pcm_ret)
*/
void line6_pcm_disconnect(struct snd_line6_pcm *line6pcm)
{
	line6_unlink_wait_clear_audio_out_urbs(line6pcm);
	line6_unlink_wait_clear_audio_in_urbs(line6pcm);
	line6_unlink_audio_urbs(line6pcm, &line6pcm->out);
	line6_unlink_audio_urbs(line6pcm, &line6pcm->in);
	line6_wait_clear_audio_urbs(line6pcm, &line6pcm->out);
	line6_wait_clear_audio_urbs(line6pcm, &line6pcm->in);
}

/*
@@ -451,15 +497,17 @@ int snd_line6_prepare(struct snd_pcm_substream *substream)

	switch (substream->stream) {
	case SNDRV_PCM_STREAM_PLAYBACK:
		if ((line6pcm->flags & LINE6_BITS_PLAYBACK_STREAM) == 0)
			line6_unlink_wait_clear_audio_out_urbs(line6pcm);

		if ((line6pcm->flags & LINE6_BITS_PLAYBACK_STREAM) == 0) {
			line6_unlink_audio_urbs(line6pcm, &line6pcm->out);
			line6_wait_clear_audio_urbs(line6pcm, &line6pcm->out);
		}
		break;

	case SNDRV_PCM_STREAM_CAPTURE:
		if ((line6pcm->flags & LINE6_BITS_CAPTURE_STREAM) == 0)
			line6_unlink_wait_clear_audio_in_urbs(line6pcm);

		if ((line6pcm->flags & LINE6_BITS_CAPTURE_STREAM) == 0) {
			line6_unlink_audio_urbs(line6pcm, &line6pcm->in);
			line6_wait_clear_audio_urbs(line6pcm, &line6pcm->in);
		}
		break;
	}

+0 −52
Original line number Diff line number Diff line
@@ -290,58 +290,6 @@ int line6_submit_audio_out_all_urbs(struct snd_line6_pcm *line6pcm)
	return 0;
}

/*
	Unlink all currently active playback URBs.
*/
void line6_unlink_audio_out_urbs(struct snd_line6_pcm *line6pcm)
{
	unsigned int i;

	for (i = 0; i < LINE6_ISO_BUFFERS; i++) {
		if (test_bit(i, &line6pcm->out.active_urbs)) {
			if (!test_and_set_bit(i, &line6pcm->out.unlink_urbs)) {
				struct urb *u = line6pcm->out.urbs[i];

				usb_unlink_urb(u);
			}
		}
	}
}

/*
	Wait until unlinking of all currently active playback URBs has been
	finished.
*/
void line6_wait_clear_audio_out_urbs(struct snd_line6_pcm *line6pcm)
{
	int timeout = HZ;
	unsigned int i;
	int alive;

	do {
		alive = 0;
		for (i = 0; i < LINE6_ISO_BUFFERS; i++) {
			if (test_bit(i, &line6pcm->out.active_urbs))
				alive++;
		}
		if (!alive)
			break;
		set_current_state(TASK_UNINTERRUPTIBLE);
		schedule_timeout(1);
	} while (--timeout > 0);
	if (alive)
		snd_printk(KERN_ERR "timeout: still %d active urbs..\n", alive);
}

/*
	Unlink all currently active playback URBs, and wait for finishing.
*/
void line6_unlink_wait_clear_audio_out_urbs(struct snd_line6_pcm *line6pcm)
{
	line6_unlink_audio_out_urbs(line6pcm);
	line6_wait_clear_audio_out_urbs(line6pcm);
}

void line6_free_playback_buffer(struct snd_line6_pcm *line6pcm)
{
	kfree(line6pcm->out.buffer);
+0 −4
Original line number Diff line number Diff line
@@ -32,10 +32,6 @@ extern struct snd_pcm_ops snd_line6_playback_ops;
extern int line6_create_audio_out_urbs(struct snd_line6_pcm *line6pcm);
extern void line6_free_playback_buffer(struct snd_line6_pcm *line6pcm);
extern int line6_submit_audio_out_all_urbs(struct snd_line6_pcm *line6pcm);
extern void line6_unlink_audio_out_urbs(struct snd_line6_pcm *line6pcm);
extern void line6_unlink_wait_clear_audio_out_urbs(struct snd_line6_pcm
						   *line6pcm);
extern void line6_wait_clear_audio_out_urbs(struct snd_line6_pcm *line6pcm);
extern int snd_line6_playback_trigger(struct snd_line6_pcm *line6pcm, int cmd);

#endif