| /* | 
 |  * Line 6 Linux USB driver | 
 |  * | 
 |  * Copyright (C) 2004-2010 Markus Grabner (grabner@icg.tugraz.at) | 
 |  * | 
 |  *	This program is free software; you can redistribute it and/or | 
 |  *	modify it under the terms of the GNU General Public License as | 
 |  *	published by the Free Software Foundation, version 2. | 
 |  * | 
 |  */ | 
 |  | 
 | /* | 
 | 	PCM interface to POD series devices. | 
 | */ | 
 |  | 
 | #ifndef PCM_H | 
 | #define PCM_H | 
 |  | 
 | #include <sound/pcm.h> | 
 |  | 
 | #include "driver.h" | 
 |  | 
 | /* | 
 | 	number of USB frames per URB | 
 | 	The Line 6 Windows driver always transmits two frames per packet, but | 
 | 	the Linux driver performs significantly better (i.e., lower latency) | 
 | 	with only one frame per packet. | 
 | */ | 
 | #define LINE6_ISO_PACKETS	1 | 
 |  | 
 | /* in a "full speed" device (such as the PODxt Pro) this means 1ms, | 
 |  *  for "high speed" it's 1/8ms | 
 |  */ | 
 | #define LINE6_ISO_INTERVAL	1 | 
 |  | 
 | #define LINE6_IMPULSE_DEFAULT_PERIOD 100 | 
 |  | 
 | /* | 
 | 	Get substream from Line 6 PCM data structure | 
 | */ | 
 | #define get_substream(line6pcm, stream)	\ | 
 | 		(line6pcm->pcm->streams[stream].substream) | 
 |  | 
 | /* | 
 | 	PCM mode bits. | 
 |  | 
 | 	There are several features of the Line 6 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 two bit flags, "opened" and "running", for each playback | 
 | 	or capture stream.  Both can contain the bit flag corresponding to | 
 | 	LINE6_STREAM_* type, | 
 | 	  LINE6_STREAM_PCM = ALSA PCM playback or capture | 
 | 	  LINE6_STREAM_MONITOR = software monitoring | 
 | 	  IMPULSE = optional impulse response measurement | 
 | 	The opened flag indicates whether the buffer is allocated while | 
 | 	the running flag indicates whether the stream is running. | 
 |  | 
 | 	For monitor or impulse operations, the driver needs to call | 
 | 	line6_pcm_acquire() or line6_pcm_release() with the appropriate | 
 | 	LINE6_STREAM_* flag. | 
 | */ | 
 |  | 
 | /* stream types */ | 
 | enum { | 
 | 	LINE6_STREAM_PCM, | 
 | 	LINE6_STREAM_MONITOR, | 
 | 	LINE6_STREAM_IMPULSE, | 
 | 	LINE6_STREAM_CAPTURE_HELPER, | 
 | }; | 
 |  | 
 | /* misc bit flags for PCM operation */ | 
 | enum { | 
 | 	LINE6_FLAG_PAUSE_PLAYBACK, | 
 | 	LINE6_FLAG_PREPARED, | 
 | }; | 
 |  | 
 | struct line6_pcm_properties { | 
 | 	struct snd_pcm_hardware playback_hw, capture_hw; | 
 | 	struct snd_pcm_hw_constraint_ratdens rates; | 
 | 	int bytes_per_channel; | 
 | }; | 
 |  | 
 | struct line6_pcm_stream { | 
 | 	/* allocated URBs */ | 
 | 	struct urb **urbs; | 
 |  | 
 | 	/* Temporary buffer; | 
 | 	 * Since the packet size is not known in advance, this buffer is | 
 | 	 * large enough to store maximum size packets. | 
 | 	 */ | 
 | 	unsigned char *buffer; | 
 |  | 
 | 	/* Free frame position in the buffer. */ | 
 | 	snd_pcm_uframes_t pos; | 
 |  | 
 | 	/* Count processed bytes; | 
 | 	 * This is modulo period size (to determine when a period is finished). | 
 | 	 */ | 
 | 	unsigned bytes; | 
 |  | 
 | 	/* Counter to create desired sample rate */ | 
 | 	unsigned count; | 
 |  | 
 | 	/* period size in bytes */ | 
 | 	unsigned period; | 
 |  | 
 | 	/* Processed frame position in the buffer; | 
 | 	 * The contents of the ring buffer have been consumed by the USB | 
 | 	 * subsystem (i.e., sent to the USB device) up to this position. | 
 | 	 */ | 
 | 	snd_pcm_uframes_t pos_done; | 
 |  | 
 | 	/* Bit mask of active URBs */ | 
 | 	unsigned long active_urbs; | 
 |  | 
 | 	/* Bit mask of URBs currently being unlinked */ | 
 | 	unsigned long unlink_urbs; | 
 |  | 
 | 	/* Spin lock to protect updates of the buffer positions (not contents) | 
 | 	 */ | 
 | 	spinlock_t lock; | 
 |  | 
 | 	/* Bit flags for operational stream types */ | 
 | 	unsigned long opened; | 
 |  | 
 | 	/* Bit flags for running stream types */ | 
 | 	unsigned long running; | 
 |  | 
 | 	int last_frame; | 
 | }; | 
 |  | 
 | struct snd_line6_pcm { | 
 | 	/* Pointer back to the Line 6 driver data structure */ | 
 | 	struct usb_line6 *line6; | 
 |  | 
 | 	/* Properties. */ | 
 | 	struct line6_pcm_properties *properties; | 
 |  | 
 | 	/* ALSA pcm stream */ | 
 | 	struct snd_pcm *pcm; | 
 |  | 
 | 	/* protection to state changes of in/out streams */ | 
 | 	struct mutex state_mutex; | 
 |  | 
 | 	/* Capture and playback streams */ | 
 | 	struct line6_pcm_stream in; | 
 | 	struct line6_pcm_stream out; | 
 |  | 
 | 	/* Previously captured frame (for software monitoring) */ | 
 | 	unsigned char *prev_fbuf; | 
 |  | 
 | 	/* Size of previously captured frame (for software monitoring/sync) */ | 
 | 	int prev_fsize; | 
 |  | 
 | 	/* Maximum size of USB packet */ | 
 | 	int max_packet_size_in; | 
 | 	int max_packet_size_out; | 
 |  | 
 | 	/* PCM playback volume (left and right) */ | 
 | 	int volume_playback[2]; | 
 |  | 
 | 	/* PCM monitor volume */ | 
 | 	int volume_monitor; | 
 |  | 
 | 	/* Volume of impulse response test signal (if zero, test is disabled) */ | 
 | 	int impulse_volume; | 
 |  | 
 | 	/* Period of impulse response test signal */ | 
 | 	int impulse_period; | 
 |  | 
 | 	/* Counter for impulse response test signal */ | 
 | 	int impulse_count; | 
 |  | 
 | 	/* Several status bits (see LINE6_FLAG_*) */ | 
 | 	unsigned long flags; | 
 | }; | 
 |  | 
 | extern int line6_init_pcm(struct usb_line6 *line6, | 
 | 			  struct line6_pcm_properties *properties); | 
 | extern int snd_line6_trigger(struct snd_pcm_substream *substream, int cmd); | 
 | extern int snd_line6_prepare(struct snd_pcm_substream *substream); | 
 | extern int snd_line6_hw_params(struct snd_pcm_substream *substream, | 
 | 			       struct snd_pcm_hw_params *hw_params); | 
 | 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 void line6_pcm_disconnect(struct snd_line6_pcm *line6pcm); | 
 | 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); | 
 |  | 
 | #endif |