Commit 0ca54888 authored by Markus Grabner's avatar Markus Grabner Committed by Greg Kroah-Hartman
Browse files

staging: line6: separate handling of buffer allocation and stream startup



There are several features of the Line6 USB driver which require PCM
data to be exchanged with the device:
*) PCM playback and capture via ALSA
*) software monitoring (for devices without hardware monitoring)
*) optional impulse response measurement
However, from the device's point of view, there is just a single
capture and playback stream, which must be shared between these
subsystems. It is therefore necessary to maintain the state of the
subsystems with respect to PCM usage. We define several constants of
the form LINE6_BIT_PCM_<subsystem>_<direction>_<resource> with the
following meanings:
*) <subsystem> is one of
-) ALSA: PCM playback and capture via ALSA
-) MONITOR: software monitoring
-) IMPULSE: optional impulse response measurement
*) <direction> is one of
-) PLAYBACK: audio output (from host to device)
-) CAPTURE: audio input (from device to host)
*) <resource> is one of
-) BUFFER: buffer required by PCM data stream
-) STREAM: actual PCM data stream

The subsystems call line6_pcm_acquire() to acquire the (shared)
resources needed for a particular operation (e.g., allocate the buffer
for ALSA playback or start the capture stream for software monitoring).
When a resource is no longer needed, it is released by calling
line6_pcm_release(). Buffer allocation and stream startup are handled
separately to allow the ALSA kernel driver to perform them at
appropriate places (since the callback which starts a PCM stream is not
allowed to sleep).

Signed-off-by: default avatarMarkus Grabner <grabner@icg.tugraz.at>
Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@linuxfoundation.org>
parent 12177acd
Loading
Loading
Loading
Loading
+15 −39
Original line number Diff line number Diff line
@@ -107,7 +107,7 @@ void line6_unlink_audio_in_urbs(struct snd_line6_pcm *line6pcm)
	Wait until unlinking of all currently active capture URBs has been
	finished.
*/
static void wait_clear_audio_in_urbs(struct snd_line6_pcm *line6pcm)
void line6_wait_clear_audio_in_urbs(struct snd_line6_pcm *line6pcm)
{
	int timeout = HZ;
	unsigned int i;
@@ -134,7 +134,7 @@ static void wait_clear_audio_in_urbs(struct snd_line6_pcm *line6pcm)
void line6_unlink_wait_clear_audio_in_urbs(struct snd_line6_pcm *line6pcm)
{
	line6_unlink_audio_in_urbs(line6pcm);
	wait_clear_audio_in_urbs(line6pcm);
	line6_wait_clear_audio_in_urbs(line6pcm);
}

/*
@@ -193,25 +193,6 @@ void line6_capture_check_period(struct snd_line6_pcm *line6pcm, int length)
	}
}

int line6_alloc_capture_buffer(struct snd_line6_pcm *line6pcm)
{
	/* We may be invoked multiple times in a row so allocate once only */
	if (line6pcm->buffer_in)
		return 0;

	line6pcm->buffer_in =
		kmalloc(LINE6_ISO_BUFFERS * LINE6_ISO_PACKETS *
			line6pcm->max_packet_size, GFP_KERNEL);

	if (!line6pcm->buffer_in) {
		dev_err(line6pcm->line6->ifcdev,
			"cannot malloc capture buffer\n");
		return -ENOMEM;
	}

	return 0;
}

void line6_free_capture_buffer(struct snd_line6_pcm *line6pcm)
{
	kfree(line6pcm->buffer_in);
@@ -273,9 +254,9 @@ static void audio_in_callback(struct urb *urb)
		line6pcm->prev_fsize = fsize;

#ifdef CONFIG_LINE6_USB_IMPULSE_RESPONSE
		if (!(line6pcm->flags & MASK_PCM_IMPULSE))
		if (!(line6pcm->flags & LINE6_BITS_PCM_IMPULSE))
#endif
			if (test_bit(BIT_PCM_ALSA_CAPTURE, &line6pcm->flags)
			if (test_bit(LINE6_INDEX_PCM_ALSA_CAPTURE_STREAM, &line6pcm->flags)
			    && (fsize > 0))
				line6_capture_copy(line6pcm, fbuf, fsize);
	}
@@ -291,9 +272,9 @@ static void audio_in_callback(struct urb *urb)
		submit_audio_in_urb(line6pcm);

#ifdef CONFIG_LINE6_USB_IMPULSE_RESPONSE
		if (!(line6pcm->flags & MASK_PCM_IMPULSE))
		if (!(line6pcm->flags & LINE6_BITS_PCM_IMPULSE))
#endif
			if (test_bit(BIT_PCM_ALSA_CAPTURE, &line6pcm->flags))
			if (test_bit(LINE6_INDEX_PCM_ALSA_CAPTURE_STREAM, &line6pcm->flags))
				line6_capture_check_period(line6pcm, length);
	}
}
@@ -341,17 +322,17 @@ static int snd_line6_capture_hw_params(struct snd_pcm_substream *substream,
	}
	/* -- [FD] end */

	if ((line6pcm->flags & MASK_CAPTURE) == 0) {
		ret = line6_alloc_capture_buffer(line6pcm);
	ret = line6_pcm_acquire(line6pcm, LINE6_BIT_PCM_ALSA_CAPTURE_BUFFER);

	if (ret < 0)
		return ret;
	}

	ret = snd_pcm_lib_malloc_pages(substream,
				       params_buffer_bytes(hw_params));
	if (ret < 0)
	if (ret < 0) {
		line6_pcm_release(line6pcm, LINE6_BIT_PCM_ALSA_CAPTURE_BUFFER);
		return ret;
	}

	line6pcm->period_in = params_period_bytes(hw_params);
	return 0;
@@ -361,12 +342,7 @@ static int snd_line6_capture_hw_params(struct snd_pcm_substream *substream,
static int snd_line6_capture_hw_free(struct snd_pcm_substream *substream)
{
	struct snd_line6_pcm *line6pcm = snd_pcm_substream_chip(substream);

	if ((line6pcm->flags & MASK_CAPTURE) == 0) {
		line6_unlink_wait_clear_audio_in_urbs(line6pcm);
		line6_free_capture_buffer(line6pcm);
	}

	line6_pcm_release(line6pcm, LINE6_BIT_PCM_ALSA_CAPTURE_BUFFER);
	return snd_pcm_lib_free_pages(substream);
}

@@ -380,7 +356,7 @@ int snd_line6_capture_trigger(struct snd_line6_pcm *line6pcm, int cmd)
#ifdef CONFIG_PM
	case SNDRV_PCM_TRIGGER_RESUME:
#endif
		err = line6_pcm_start(line6pcm, MASK_PCM_ALSA_CAPTURE);
		err = line6_pcm_acquire(line6pcm, LINE6_BIT_PCM_ALSA_CAPTURE_STREAM);

		if (err < 0)
			return err;
@@ -391,7 +367,7 @@ int snd_line6_capture_trigger(struct snd_line6_pcm *line6pcm, int cmd)
#ifdef CONFIG_PM
	case SNDRV_PCM_TRIGGER_SUSPEND:
#endif
		err = line6_pcm_stop(line6pcm, MASK_PCM_ALSA_CAPTURE);
		err = line6_pcm_release(line6pcm, LINE6_BIT_PCM_ALSA_CAPTURE_STREAM);

		if (err < 0)
			return err;
+1 −1
Original line number Diff line number Diff line
@@ -19,7 +19,6 @@

extern struct snd_pcm_ops snd_line6_capture_ops;

extern int line6_alloc_capture_buffer(struct snd_line6_pcm *line6pcm);
extern void line6_capture_copy(struct snd_line6_pcm *line6pcm, char *fbuf,
			       int fsize);
extern void line6_capture_check_period(struct snd_line6_pcm *line6pcm,
@@ -30,6 +29,7 @@ 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
+1 −1
Original line number Diff line number Diff line
@@ -1346,7 +1346,7 @@ static void __exit line6_exit(void)
		if (line6pcm == NULL)
			continue;

		line6_pcm_stop(line6pcm, ~0);
		line6_pcm_release(line6pcm, ~0);
	}

	usb_deregister(&line6_driver);
+73 −36
Original line number Diff line number Diff line
@@ -52,9 +52,9 @@ static ssize_t pcm_set_impulse_volume(struct device *dev,
	line6pcm->impulse_volume = value;

	if (value > 0)
		line6_pcm_start(line6pcm, MASK_PCM_IMPULSE);
		line6_pcm_acquire(line6pcm, LINE6_BITS_PCM_IMPULSE);
	else
		line6_pcm_stop(line6pcm, MASK_PCM_IMPULSE);
		line6_pcm_release(line6pcm, LINE6_BITS_PCM_IMPULSE);

	return count;
}
@@ -92,29 +92,43 @@ static bool test_flags(unsigned long flags0, unsigned long flags1,
	return ((flags0 & mask) == 0) && ((flags1 & mask) != 0);
}

int line6_pcm_start(struct snd_line6_pcm *line6pcm, int channels)
int line6_pcm_acquire(struct snd_line6_pcm *line6pcm, int channels)
{
	unsigned long flags_old =
	    __sync_fetch_and_or(&line6pcm->flags, channels);
	unsigned long flags_new = flags_old | channels;
	unsigned long flags_final = flags_old;
	int err = 0;
	
	line6pcm->prev_fbuf = NULL;

	if (test_flags(flags_old, flags_new, MASK_CAPTURE)) {
	if (test_flags(flags_old, flags_new, LINE6_BITS_CAPTURE_BUFFER)) {
		/* We may be invoked multiple times in a row so allocate once only */
		if (!line6pcm->buffer_in) {
			line6pcm->buffer_in =
				kmalloc(LINE6_ISO_BUFFERS * LINE6_ISO_PACKETS *
					line6pcm->max_packet_size, GFP_KERNEL);

			if (!line6pcm->buffer_in) {
				dev_err(line6pcm->line6->ifcdev,
					"cannot malloc capture buffer\n");
				err = -ENOMEM;
				goto pcm_acquire_error;
			}

			flags_final |= channels & LINE6_BITS_CAPTURE_BUFFER;
		}
	}

	if (test_flags(flags_old, flags_new, LINE6_BITS_CAPTURE_STREAM)) {
		/*
		   Waiting for completion of active URBs in the stop handler is
		   a bug, we therefore report an error if capturing is restarted
		   too soon.
		 */
		if (line6pcm->active_urb_in | line6pcm->unlink_urb_in)
		if (line6pcm->active_urb_in | line6pcm->unlink_urb_in) {
			dev_err(line6pcm->line6->ifcdev, "Device not yet ready\n");
			return -EBUSY;

		if (!(flags_new & MASK_PCM_ALSA_CAPTURE)) {
			err = line6_alloc_capture_buffer(line6pcm);

			if (err < 0)
				goto pcm_start_error;
		}

		line6pcm->count_in = 0;
@@ -122,54 +136,77 @@ int line6_pcm_start(struct snd_line6_pcm *line6pcm, int channels)
		err = line6_submit_audio_in_all_urbs(line6pcm);

		if (err < 0)
			goto pcm_start_error;
			goto pcm_acquire_error;

		flags_final |= channels & LINE6_BITS_CAPTURE_STREAM;
	}

	if (test_flags(flags_old, flags_new, MASK_PLAYBACK)) {
	if (test_flags(flags_old, flags_new, LINE6_BITS_PLAYBACK_BUFFER)) {
		/* We may be invoked multiple times in a row so allocate once only */
		if (!line6pcm->buffer_out) {
			line6pcm->buffer_out =
				kmalloc(LINE6_ISO_BUFFERS * LINE6_ISO_PACKETS *
					line6pcm->max_packet_size, GFP_KERNEL);

			if (!line6pcm->buffer_out) {
				dev_err(line6pcm->line6->ifcdev,
					"cannot malloc playback buffer\n");
				err = -ENOMEM;
				goto pcm_acquire_error;
			}

			flags_final |= channels & LINE6_BITS_PLAYBACK_BUFFER;
		}
	}

	if (test_flags(flags_old, flags_new, LINE6_BITS_PLAYBACK_STREAM)) {
		/*
		  See comment above regarding PCM restart.
		*/
		if (line6pcm->active_urb_out | line6pcm->unlink_urb_out)
		if (line6pcm->active_urb_out | line6pcm->unlink_urb_out) {
			dev_err(line6pcm->line6->ifcdev, "Device not yet ready\n");
			return -EBUSY;

		if (!(flags_new & MASK_PCM_ALSA_PLAYBACK)) {
			err = line6_alloc_playback_buffer(line6pcm);

			if (err < 0)
				goto pcm_start_error;
		}

		line6pcm->count_out = 0;
		err = line6_submit_audio_out_all_urbs(line6pcm);

		if (err < 0)
			goto pcm_start_error;
			goto pcm_acquire_error;

		flags_final |= channels & LINE6_BITS_PLAYBACK_STREAM;
	}

	return 0;

pcm_start_error:
	__sync_fetch_and_and(&line6pcm->flags, ~channels);
pcm_acquire_error:
	/*
	   If not all requested resources/streams could be obtained, release
	   those which were successfully obtained (if any).
	*/
	line6_pcm_release(line6pcm, flags_final & channels);
	return err;
}

int line6_pcm_stop(struct snd_line6_pcm *line6pcm, int channels)
int line6_pcm_release(struct snd_line6_pcm *line6pcm, int channels)
{
	unsigned long flags_old =
	    __sync_fetch_and_and(&line6pcm->flags, ~channels);
	unsigned long flags_new = flags_old & ~channels;

	if (test_flags(flags_new, flags_old, MASK_CAPTURE)) {
	if (test_flags(flags_new, flags_old, LINE6_BITS_CAPTURE_STREAM))
		line6_unlink_audio_in_urbs(line6pcm);

		if (!(flags_old & MASK_PCM_ALSA_CAPTURE))
	if (test_flags(flags_new, flags_old, LINE6_BITS_CAPTURE_BUFFER)) {
		line6_wait_clear_audio_in_urbs(line6pcm);
		line6_free_capture_buffer(line6pcm);
	}

	if (test_flags(flags_new, flags_old, MASK_PLAYBACK)) {
	if (test_flags(flags_new, flags_old, LINE6_BITS_PLAYBACK_STREAM))
		line6_unlink_audio_out_urbs(line6pcm);

		if (!(flags_old & MASK_PCM_ALSA_PLAYBACK))
	if (test_flags(flags_new, flags_old, LINE6_BITS_PLAYBACK_BUFFER)) {
		line6_wait_clear_audio_out_urbs(line6pcm);
		line6_free_playback_buffer(line6pcm);
	}

@@ -185,7 +222,7 @@ int snd_line6_trigger(struct snd_pcm_substream *substream, int cmd)
	unsigned long flags;

	spin_lock_irqsave(&line6pcm->lock_trigger, flags);
	clear_bit(BIT_PREPARED, &line6pcm->flags);
	clear_bit(LINE6_INDEX_PREPARED, &line6pcm->flags);

	snd_pcm_group_for_each_entry(s, substream) {
		switch (s->stream) {
@@ -498,13 +535,13 @@ int snd_line6_prepare(struct snd_pcm_substream *substream)

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

		break;

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

		break;
@@ -513,7 +550,7 @@ int snd_line6_prepare(struct snd_pcm_substream *substream)
		MISSING_CASE;
	}

	if (!test_and_set_bit(BIT_PREPARED, &line6pcm->flags)) {
	if (!test_and_set_bit(LINE6_INDEX_PREPARED, &line6pcm->flags)) {
		line6pcm->count_out = 0;
		line6pcm->pos_out = 0;
		line6pcm->pos_out_done = 0;
+116 −42
Original line number Diff line number Diff line
@@ -46,57 +46,131 @@
		(line6pcm->pcm->streams[stream].substream)

/*
	PCM mode bits and masks.
	"ALSA": operations triggered by applications via ALSA
	"MONITOR": software monitoring
	"IMPULSE": optional impulse response operation
	PCM mode bits.

	There are several features of the Line6 USB driver which require PCM
	data to be exchanged with the device:
	*) PCM playback and capture via ALSA
	*) software monitoring (for devices without hardware monitoring)
	*) optional impulse response measurement
	However, from the device's point of view, there is just a single
	capture and playback stream, which must be shared between these
	subsystems. It is therefore necessary to maintain the state of the
	subsystems with respect to PCM usage. We define several constants of
	the form LINE6_BIT_PCM_<subsystem>_<direction>_<resource> with the
	following meanings:
	*) <subsystem> is one of
	-) ALSA: PCM playback and capture via ALSA
	-) MONITOR: software monitoring
	-) IMPULSE: optional impulse response measurement
	*) <direction> is one of
	-) PLAYBACK: audio output (from host to device)
	-) CAPTURE: audio input (from device to host)
	*) <resource> is one of
	-) BUFFER: buffer required by PCM data stream
	-) STREAM: actual PCM data stream

	The subsystems call line6_pcm_acquire() to acquire the (shared)
	resources needed for a particular operation (e.g., allocate the buffer
	for ALSA playback or start the capture stream for software monitoring).
	When a resource is no longer needed, it is released by calling
	line6_pcm_release(). Buffer allocation and stream startup are handled
	separately to allow the ALSA kernel driver to perform them at
	appropriate places (since the callback which starts a PCM stream is not
	allowed to sleep).
*/
enum {
	/* individual bits: */
	BIT_PCM_ALSA_PLAYBACK,
	BIT_PCM_ALSA_CAPTURE,
	BIT_PCM_MONITOR_PLAYBACK,
	BIT_PCM_MONITOR_CAPTURE,
	/* individual bit indices: */
	LINE6_INDEX_PCM_ALSA_PLAYBACK_BUFFER,
	LINE6_INDEX_PCM_ALSA_PLAYBACK_STREAM,
	LINE6_INDEX_PCM_ALSA_CAPTURE_BUFFER,
	LINE6_INDEX_PCM_ALSA_CAPTURE_STREAM,
	LINE6_INDEX_PCM_MONITOR_PLAYBACK_BUFFER,
	LINE6_INDEX_PCM_MONITOR_PLAYBACK_STREAM,
	LINE6_INDEX_PCM_MONITOR_CAPTURE_BUFFER,
	LINE6_INDEX_PCM_MONITOR_CAPTURE_STREAM,
#ifdef CONFIG_LINE6_USB_IMPULSE_RESPONSE
	BIT_PCM_IMPULSE_PLAYBACK,
	BIT_PCM_IMPULSE_CAPTURE,
	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
	BIT_PAUSE_PLAYBACK,
	BIT_PREPARED,

	/* individual masks: */
/* *INDENT-OFF* */
	MASK_PCM_ALSA_PLAYBACK    = 1 << BIT_PCM_ALSA_PLAYBACK,
	MASK_PCM_ALSA_CAPTURE     = 1 << BIT_PCM_ALSA_CAPTURE,
	MASK_PCM_MONITOR_PLAYBACK = 1 << BIT_PCM_MONITOR_PLAYBACK,
	MASK_PCM_MONITOR_CAPTURE  = 1 << BIT_PCM_MONITOR_CAPTURE,
	LINE6_INDEX_PAUSE_PLAYBACK,
	LINE6_INDEX_PREPARED,

	/* individual bit masks: */
	LINE6_BIT(PCM_ALSA_PLAYBACK_BUFFER),
	LINE6_BIT(PCM_ALSA_PLAYBACK_STREAM),
	LINE6_BIT(PCM_ALSA_CAPTURE_BUFFER),
	LINE6_BIT(PCM_ALSA_CAPTURE_STREAM),
	LINE6_BIT(PCM_MONITOR_PLAYBACK_BUFFER),
	LINE6_BIT(PCM_MONITOR_PLAYBACK_STREAM),
	LINE6_BIT(PCM_MONITOR_CAPTURE_BUFFER),
	LINE6_BIT(PCM_MONITOR_CAPTURE_STREAM),
#ifdef CONFIG_LINE6_USB_IMPULSE_RESPONSE
	MASK_PCM_IMPULSE_PLAYBACK = 1 << BIT_PCM_IMPULSE_PLAYBACK,
	MASK_PCM_IMPULSE_CAPTURE  = 1 << BIT_PCM_IMPULSE_CAPTURE,
	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
	MASK_PAUSE_PLAYBACK       = 1 << BIT_PAUSE_PLAYBACK,
	MASK_PREPARED             = 1 << BIT_PREPARED,
/* *INDENT-ON* */
	LINE6_BIT(PAUSE_PLAYBACK),
	LINE6_BIT(PREPARED),

	/* combined bit masks (by operation): */
	LINE6_BITS_PCM_ALSA_BUFFER =
	    LINE6_BIT_PCM_ALSA_PLAYBACK_BUFFER |
	    LINE6_BIT_PCM_ALSA_CAPTURE_BUFFER,

	LINE6_BITS_PCM_ALSA_STREAM =
	    LINE6_BIT_PCM_ALSA_PLAYBACK_STREAM |
	    LINE6_BIT_PCM_ALSA_CAPTURE_STREAM,

	LINE6_BITS_PCM_MONITOR =
	    LINE6_BIT_PCM_MONITOR_PLAYBACK_BUFFER |
	    LINE6_BIT_PCM_MONITOR_PLAYBACK_STREAM |
	    LINE6_BIT_PCM_MONITOR_CAPTURE_BUFFER |
	    LINE6_BIT_PCM_MONITOR_CAPTURE_STREAM,

	/* combined masks (by operation): */
	MASK_PCM_ALSA = MASK_PCM_ALSA_PLAYBACK | MASK_PCM_ALSA_CAPTURE,
	MASK_PCM_MONITOR = MASK_PCM_MONITOR_PLAYBACK | MASK_PCM_MONITOR_CAPTURE,
#ifdef CONFIG_LINE6_USB_IMPULSE_RESPONSE
	MASK_PCM_IMPULSE = MASK_PCM_IMPULSE_PLAYBACK | MASK_PCM_IMPULSE_CAPTURE,
	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 masks (by direction): */
	/* combined bit masks (by direction): */
	LINE6_BITS_PLAYBACK_BUFFER =
#ifdef CONFIG_LINE6_USB_IMPULSE_RESPONSE
	MASK_PLAYBACK =
	    MASK_PCM_ALSA_PLAYBACK | MASK_PCM_MONITOR_PLAYBACK |
	    MASK_PCM_IMPULSE_PLAYBACK,
	MASK_CAPTURE =
	    MASK_PCM_ALSA_CAPTURE | MASK_PCM_MONITOR_CAPTURE |
	    MASK_PCM_IMPULSE_CAPTURE
#else
	MASK_PLAYBACK = MASK_PCM_ALSA_PLAYBACK | MASK_PCM_MONITOR_PLAYBACK,
	MASK_CAPTURE = MASK_PCM_ALSA_CAPTURE | MASK_PCM_MONITOR_CAPTURE
	    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,
	
	LINE6_BITS_STREAM =
	    LINE6_BITS_PLAYBACK_STREAM |
	    LINE6_BITS_CAPTURE_STREAM
};

struct line6_pcm_properties {
@@ -290,7 +364,7 @@ struct snd_line6_pcm {
#endif

	/**
		 Several status bits (see BIT_*).
		 Several status bits (see LINE6_BIT_*).
	*/
	unsigned long flags;

@@ -302,7 +376,7 @@ extern int line6_init_pcm(struct usb_line6 *line6,
extern int snd_line6_trigger(struct snd_pcm_substream *substream, int cmd);
extern int snd_line6_prepare(struct snd_pcm_substream *substream);
extern void line6_pcm_disconnect(struct snd_line6_pcm *line6pcm);
extern int line6_pcm_start(struct snd_line6_pcm *line6pcm, int channels);
extern int line6_pcm_stop(struct snd_line6_pcm *line6pcm, int channels);
extern int line6_pcm_acquire(struct snd_line6_pcm *line6pcm, int channels);
extern int line6_pcm_release(struct snd_line6_pcm *line6pcm, int channels);

#endif
Loading