2011-03-15 09:53:21 +03:00
# ifndef SOUND_FIREWIRE_AMDTP_H_INCLUDED
# define SOUND_FIREWIRE_AMDTP_H_INCLUDED
2011-09-05 00:15:44 +04:00
# include <linux/err.h>
2012-05-14 00:03:09 +04:00
# include <linux/interrupt.h>
2011-03-15 09:53:21 +03:00
# include <linux/mutex.h>
2013-11-19 08:29:24 +04:00
# include <sound/asound.h>
2011-03-15 09:53:21 +03:00
# include "packets-buffer.h"
/**
* enum cip_out_flags - describes details of the streaming protocol
* @ CIP_NONBLOCKING : In non - blocking mode , each packet contains
* sample_rate / 8000 samples , with rounding up or down to adjust
* for clock skew and left - over fractional samples . This should
* be used if supported by the device .
2011-09-05 00:12:48 +04:00
* @ CIP_BLOCKING : In blocking mode , each packet contains either zero or
* SYT_INTERVAL samples , with these two types alternating so that
* the overall sample rate comes out right .
2011-09-05 00:16:10 +04:00
* @ CIP_HI_DUALWIRE : At rates above 96 kHz , pretend that the stream runs
* at half the actual sample rate with twice the number of channels ;
* two samples of a channel are stored consecutively in the packet .
* Requires blocking mode and SYT_INTERVAL - aligned PCM buffer size .
2011-03-15 09:53:21 +03:00
*/
enum cip_out_flags {
2011-09-05 00:12:48 +04:00
CIP_NONBLOCKING = 0x00 ,
CIP_BLOCKING = 0x01 ,
2011-09-05 00:16:10 +04:00
CIP_HI_DUALWIRE = 0x02 ,
2011-03-15 09:53:21 +03:00
} ;
/**
* enum cip_sfc - a stream ' s sample rate
*/
enum cip_sfc {
CIP_SFC_32000 = 0 ,
CIP_SFC_44100 = 1 ,
CIP_SFC_48000 = 2 ,
CIP_SFC_88200 = 3 ,
CIP_SFC_96000 = 4 ,
CIP_SFC_176400 = 5 ,
CIP_SFC_192000 = 6 ,
2011-09-05 00:16:10 +04:00
CIP_SFC_COUNT
2011-03-15 09:53:21 +03:00
} ;
# define AMDTP_OUT_PCM_FORMAT_BITS (SNDRV_PCM_FMTBIT_S16 | \
SNDRV_PCM_FMTBIT_S32 )
struct fw_unit ;
struct fw_iso_context ;
struct snd_pcm_substream ;
struct amdtp_out_stream {
struct fw_unit * unit ;
enum cip_out_flags flags ;
struct fw_iso_context * context ;
struct mutex mutex ;
enum cip_sfc sfc ;
2011-09-05 00:16:10 +04:00
bool dual_wire ;
2011-03-15 09:53:21 +03:00
unsigned int data_block_quadlets ;
unsigned int pcm_channels ;
unsigned int midi_ports ;
void ( * transfer_samples ) ( struct amdtp_out_stream * s ,
struct snd_pcm_substream * pcm ,
__be32 * buffer , unsigned int frames ) ;
unsigned int syt_interval ;
2011-09-05 00:12:48 +04:00
unsigned int transfer_delay ;
2011-03-15 09:53:21 +03:00
unsigned int source_node_id_field ;
struct iso_packets_buffer buffer ;
struct snd_pcm_substream * pcm ;
2012-05-14 00:03:09 +04:00
struct tasklet_struct period_tasklet ;
2011-03-15 09:53:21 +03:00
2011-03-15 09:57:24 +03:00
int packet_index ;
2011-03-15 09:53:21 +03:00
unsigned int data_block_counter ;
unsigned int data_block_state ;
unsigned int last_syt_offset ;
unsigned int syt_offset_state ;
unsigned int pcm_buffer_pointer ;
unsigned int pcm_period_pointer ;
2012-05-13 21:07:22 +04:00
bool pointer_flush ;
2011-03-15 09:53:21 +03:00
} ;
int amdtp_out_stream_init ( struct amdtp_out_stream * s , struct fw_unit * unit ,
enum cip_out_flags flags ) ;
void amdtp_out_stream_destroy ( struct amdtp_out_stream * s ) ;
2011-09-05 00:16:10 +04:00
void amdtp_out_stream_set_parameters ( struct amdtp_out_stream * s ,
unsigned int rate ,
unsigned int pcm_channels ,
unsigned int midi_ports ) ;
2011-03-15 09:53:21 +03:00
unsigned int amdtp_out_stream_get_max_payload ( struct amdtp_out_stream * s ) ;
int amdtp_out_stream_start ( struct amdtp_out_stream * s , int channel , int speed ) ;
void amdtp_out_stream_update ( struct amdtp_out_stream * s ) ;
void amdtp_out_stream_stop ( struct amdtp_out_stream * s ) ;
void amdtp_out_stream_set_pcm_format ( struct amdtp_out_stream * s ,
snd_pcm_format_t format ) ;
2012-05-14 00:03:09 +04:00
void amdtp_out_stream_pcm_prepare ( struct amdtp_out_stream * s ) ;
2012-05-13 20:49:14 +04:00
unsigned long amdtp_out_stream_pcm_pointer ( struct amdtp_out_stream * s ) ;
2011-03-15 09:53:21 +03:00
void amdtp_out_stream_pcm_abort ( struct amdtp_out_stream * s ) ;
2011-10-16 23:39:00 +04:00
extern const unsigned int amdtp_syt_intervals [ CIP_SFC_COUNT ] ;
2011-09-05 00:16:10 +04:00
2011-09-05 00:15:44 +04:00
static inline bool amdtp_out_stream_running ( struct amdtp_out_stream * s )
{
return ! IS_ERR ( s - > context ) ;
}
2011-03-15 09:57:24 +03:00
/**
* amdtp_out_streaming_error - check for streaming error
* @ s : the AMDTP output stream
*
* If this function returns true , the stream ' s packet queue has stopped due to
* an asynchronous error .
*/
static inline bool amdtp_out_streaming_error ( struct amdtp_out_stream * s )
{
return s - > packet_index < 0 ;
}
2011-03-15 09:53:21 +03:00
/**
* amdtp_out_stream_pcm_trigger - start / stop playback from a PCM device
* @ s : the AMDTP output stream
* @ pcm : the PCM device to be started , or % NULL to stop the current device
*
* Call this function on a running isochronous stream to enable the actual
* transmission of PCM data . This function should be called from the PCM
* device ' s . trigger callback .
*/
static inline void amdtp_out_stream_pcm_trigger ( struct amdtp_out_stream * s ,
struct snd_pcm_substream * pcm )
{
ACCESS_ONCE ( s - > pcm ) = pcm ;
}
static inline bool cip_sfc_is_base_44100 ( enum cip_sfc sfc )
{
return sfc & 1 ;
}
# endif