162306a36Sopenharmony_ci/* SPDX-License-Identifier: GPL-2.0-only */
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * Line 6 Linux USB driver
462306a36Sopenharmony_ci *
562306a36Sopenharmony_ci * Copyright (C) 2004-2010 Markus Grabner (grabner@icg.tugraz.at)
662306a36Sopenharmony_ci */
762306a36Sopenharmony_ci
862306a36Sopenharmony_ci/*
962306a36Sopenharmony_ci	PCM interface to POD series devices.
1062306a36Sopenharmony_ci*/
1162306a36Sopenharmony_ci
1262306a36Sopenharmony_ci#ifndef PCM_H
1362306a36Sopenharmony_ci#define PCM_H
1462306a36Sopenharmony_ci
1562306a36Sopenharmony_ci#include <sound/pcm.h>
1662306a36Sopenharmony_ci
1762306a36Sopenharmony_ci#include "driver.h"
1862306a36Sopenharmony_ci
1962306a36Sopenharmony_ci/*
2062306a36Sopenharmony_ci	number of USB frames per URB
2162306a36Sopenharmony_ci	The Line 6 Windows driver always transmits two frames per packet, but
2262306a36Sopenharmony_ci	the Linux driver performs significantly better (i.e., lower latency)
2362306a36Sopenharmony_ci	with only one frame per packet.
2462306a36Sopenharmony_ci*/
2562306a36Sopenharmony_ci#define LINE6_ISO_PACKETS	1
2662306a36Sopenharmony_ci
2762306a36Sopenharmony_ci/* in a "full speed" device (such as the PODxt Pro) this means 1ms,
2862306a36Sopenharmony_ci *  for "high speed" it's 1/8ms
2962306a36Sopenharmony_ci */
3062306a36Sopenharmony_ci#define LINE6_ISO_INTERVAL	1
3162306a36Sopenharmony_ci
3262306a36Sopenharmony_ci#define LINE6_IMPULSE_DEFAULT_PERIOD 100
3362306a36Sopenharmony_ci
3462306a36Sopenharmony_ci/*
3562306a36Sopenharmony_ci	Get substream from Line 6 PCM data structure
3662306a36Sopenharmony_ci*/
3762306a36Sopenharmony_ci#define get_substream(line6pcm, stream)	\
3862306a36Sopenharmony_ci		(line6pcm->pcm->streams[stream].substream)
3962306a36Sopenharmony_ci
4062306a36Sopenharmony_ci/*
4162306a36Sopenharmony_ci	PCM mode bits.
4262306a36Sopenharmony_ci
4362306a36Sopenharmony_ci	There are several features of the Line 6 USB driver which require PCM
4462306a36Sopenharmony_ci	data to be exchanged with the device:
4562306a36Sopenharmony_ci	*) PCM playback and capture via ALSA
4662306a36Sopenharmony_ci	*) software monitoring (for devices without hardware monitoring)
4762306a36Sopenharmony_ci	*) optional impulse response measurement
4862306a36Sopenharmony_ci	However, from the device's point of view, there is just a single
4962306a36Sopenharmony_ci	capture and playback stream, which must be shared between these
5062306a36Sopenharmony_ci	subsystems. It is therefore necessary to maintain the state of the
5162306a36Sopenharmony_ci	subsystems with respect to PCM usage.
5262306a36Sopenharmony_ci
5362306a36Sopenharmony_ci	We define two bit flags, "opened" and "running", for each playback
5462306a36Sopenharmony_ci	or capture stream.  Both can contain the bit flag corresponding to
5562306a36Sopenharmony_ci	LINE6_STREAM_* type,
5662306a36Sopenharmony_ci	  LINE6_STREAM_PCM = ALSA PCM playback or capture
5762306a36Sopenharmony_ci	  LINE6_STREAM_MONITOR = software monitoring
5862306a36Sopenharmony_ci	  IMPULSE = optional impulse response measurement
5962306a36Sopenharmony_ci	The opened flag indicates whether the buffer is allocated while
6062306a36Sopenharmony_ci	the running flag indicates whether the stream is running.
6162306a36Sopenharmony_ci
6262306a36Sopenharmony_ci	For monitor or impulse operations, the driver needs to call
6362306a36Sopenharmony_ci	line6_pcm_acquire() or line6_pcm_release() with the appropriate
6462306a36Sopenharmony_ci	LINE6_STREAM_* flag.
6562306a36Sopenharmony_ci*/
6662306a36Sopenharmony_ci
6762306a36Sopenharmony_ci/* stream types */
6862306a36Sopenharmony_cienum {
6962306a36Sopenharmony_ci	LINE6_STREAM_PCM,
7062306a36Sopenharmony_ci	LINE6_STREAM_MONITOR,
7162306a36Sopenharmony_ci	LINE6_STREAM_IMPULSE,
7262306a36Sopenharmony_ci	LINE6_STREAM_CAPTURE_HELPER,
7362306a36Sopenharmony_ci};
7462306a36Sopenharmony_ci
7562306a36Sopenharmony_ci/* misc bit flags for PCM operation */
7662306a36Sopenharmony_cienum {
7762306a36Sopenharmony_ci	LINE6_FLAG_PAUSE_PLAYBACK,
7862306a36Sopenharmony_ci	LINE6_FLAG_PREPARED,
7962306a36Sopenharmony_ci};
8062306a36Sopenharmony_ci
8162306a36Sopenharmony_cistruct line6_pcm_properties {
8262306a36Sopenharmony_ci	struct snd_pcm_hardware playback_hw, capture_hw;
8362306a36Sopenharmony_ci	struct snd_pcm_hw_constraint_ratdens rates;
8462306a36Sopenharmony_ci	int bytes_per_channel;
8562306a36Sopenharmony_ci};
8662306a36Sopenharmony_ci
8762306a36Sopenharmony_cistruct line6_pcm_stream {
8862306a36Sopenharmony_ci	/* allocated URBs */
8962306a36Sopenharmony_ci	struct urb **urbs;
9062306a36Sopenharmony_ci
9162306a36Sopenharmony_ci	/* Temporary buffer;
9262306a36Sopenharmony_ci	 * Since the packet size is not known in advance, this buffer is
9362306a36Sopenharmony_ci	 * large enough to store maximum size packets.
9462306a36Sopenharmony_ci	 */
9562306a36Sopenharmony_ci	unsigned char *buffer;
9662306a36Sopenharmony_ci
9762306a36Sopenharmony_ci	/* Free frame position in the buffer. */
9862306a36Sopenharmony_ci	snd_pcm_uframes_t pos;
9962306a36Sopenharmony_ci
10062306a36Sopenharmony_ci	/* Count processed bytes;
10162306a36Sopenharmony_ci	 * This is modulo period size (to determine when a period is finished).
10262306a36Sopenharmony_ci	 */
10362306a36Sopenharmony_ci	unsigned bytes;
10462306a36Sopenharmony_ci
10562306a36Sopenharmony_ci	/* Counter to create desired sample rate */
10662306a36Sopenharmony_ci	unsigned count;
10762306a36Sopenharmony_ci
10862306a36Sopenharmony_ci	/* period size in bytes */
10962306a36Sopenharmony_ci	unsigned period;
11062306a36Sopenharmony_ci
11162306a36Sopenharmony_ci	/* Processed frame position in the buffer;
11262306a36Sopenharmony_ci	 * The contents of the ring buffer have been consumed by the USB
11362306a36Sopenharmony_ci	 * subsystem (i.e., sent to the USB device) up to this position.
11462306a36Sopenharmony_ci	 */
11562306a36Sopenharmony_ci	snd_pcm_uframes_t pos_done;
11662306a36Sopenharmony_ci
11762306a36Sopenharmony_ci	/* Bit mask of active URBs */
11862306a36Sopenharmony_ci	unsigned long active_urbs;
11962306a36Sopenharmony_ci
12062306a36Sopenharmony_ci	/* Bit mask of URBs currently being unlinked */
12162306a36Sopenharmony_ci	unsigned long unlink_urbs;
12262306a36Sopenharmony_ci
12362306a36Sopenharmony_ci	/* Spin lock to protect updates of the buffer positions (not contents)
12462306a36Sopenharmony_ci	 */
12562306a36Sopenharmony_ci	spinlock_t lock;
12662306a36Sopenharmony_ci
12762306a36Sopenharmony_ci	/* Bit flags for operational stream types */
12862306a36Sopenharmony_ci	unsigned long opened;
12962306a36Sopenharmony_ci
13062306a36Sopenharmony_ci	/* Bit flags for running stream types */
13162306a36Sopenharmony_ci	unsigned long running;
13262306a36Sopenharmony_ci
13362306a36Sopenharmony_ci	int last_frame;
13462306a36Sopenharmony_ci};
13562306a36Sopenharmony_ci
13662306a36Sopenharmony_cistruct snd_line6_pcm {
13762306a36Sopenharmony_ci	/* Pointer back to the Line 6 driver data structure */
13862306a36Sopenharmony_ci	struct usb_line6 *line6;
13962306a36Sopenharmony_ci
14062306a36Sopenharmony_ci	/* Properties. */
14162306a36Sopenharmony_ci	struct line6_pcm_properties *properties;
14262306a36Sopenharmony_ci
14362306a36Sopenharmony_ci	/* ALSA pcm stream */
14462306a36Sopenharmony_ci	struct snd_pcm *pcm;
14562306a36Sopenharmony_ci
14662306a36Sopenharmony_ci	/* protection to state changes of in/out streams */
14762306a36Sopenharmony_ci	struct mutex state_mutex;
14862306a36Sopenharmony_ci
14962306a36Sopenharmony_ci	/* Capture and playback streams */
15062306a36Sopenharmony_ci	struct line6_pcm_stream in;
15162306a36Sopenharmony_ci	struct line6_pcm_stream out;
15262306a36Sopenharmony_ci
15362306a36Sopenharmony_ci	/* Previously captured frame (for software monitoring) */
15462306a36Sopenharmony_ci	unsigned char *prev_fbuf;
15562306a36Sopenharmony_ci
15662306a36Sopenharmony_ci	/* Size of previously captured frame (for software monitoring/sync) */
15762306a36Sopenharmony_ci	int prev_fsize;
15862306a36Sopenharmony_ci
15962306a36Sopenharmony_ci	/* Maximum size of USB packet */
16062306a36Sopenharmony_ci	int max_packet_size_in;
16162306a36Sopenharmony_ci	int max_packet_size_out;
16262306a36Sopenharmony_ci
16362306a36Sopenharmony_ci	/* PCM playback volume (left and right) */
16462306a36Sopenharmony_ci	int volume_playback[2];
16562306a36Sopenharmony_ci
16662306a36Sopenharmony_ci	/* PCM monitor volume */
16762306a36Sopenharmony_ci	int volume_monitor;
16862306a36Sopenharmony_ci
16962306a36Sopenharmony_ci	/* Volume of impulse response test signal (if zero, test is disabled) */
17062306a36Sopenharmony_ci	int impulse_volume;
17162306a36Sopenharmony_ci
17262306a36Sopenharmony_ci	/* Period of impulse response test signal */
17362306a36Sopenharmony_ci	int impulse_period;
17462306a36Sopenharmony_ci
17562306a36Sopenharmony_ci	/* Counter for impulse response test signal */
17662306a36Sopenharmony_ci	int impulse_count;
17762306a36Sopenharmony_ci
17862306a36Sopenharmony_ci	/* Several status bits (see LINE6_FLAG_*) */
17962306a36Sopenharmony_ci	unsigned long flags;
18062306a36Sopenharmony_ci};
18162306a36Sopenharmony_ci
18262306a36Sopenharmony_ciextern int line6_init_pcm(struct usb_line6 *line6,
18362306a36Sopenharmony_ci			  struct line6_pcm_properties *properties);
18462306a36Sopenharmony_ciextern int snd_line6_trigger(struct snd_pcm_substream *substream, int cmd);
18562306a36Sopenharmony_ciextern int snd_line6_prepare(struct snd_pcm_substream *substream);
18662306a36Sopenharmony_ciextern int snd_line6_hw_params(struct snd_pcm_substream *substream,
18762306a36Sopenharmony_ci			       struct snd_pcm_hw_params *hw_params);
18862306a36Sopenharmony_ciextern int snd_line6_hw_free(struct snd_pcm_substream *substream);
18962306a36Sopenharmony_ciextern snd_pcm_uframes_t snd_line6_pointer(struct snd_pcm_substream *substream);
19062306a36Sopenharmony_ciextern void line6_pcm_disconnect(struct snd_line6_pcm *line6pcm);
19162306a36Sopenharmony_ciextern int line6_pcm_acquire(struct snd_line6_pcm *line6pcm, int type,
19262306a36Sopenharmony_ci			       bool start);
19362306a36Sopenharmony_ciextern void line6_pcm_release(struct snd_line6_pcm *line6pcm, int type);
19462306a36Sopenharmony_ci
19562306a36Sopenharmony_ci#endif
196