summaryrefslogtreecommitdiff
path: root/snd-pcxhr-dkms/src/pcxhr.h
blob: d55947183935758c3f55a0bad037e40e0a13aef4 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
/*
 * Driver for Digigram pcxhr soundcards
 *
 * main header file
 *
 * Copyright (c) 2004 by Digigram <alsa@digigram.com>
 *
 *   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; either version 2 of the License, or
 *   (at your option) any later version.
 *
 *   This program is distributed in the hope that it will be useful,
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *   GNU General Public License for more details.
 *
 *   You should have received a copy of the GNU General Public License
 *   along with this program; if not, write to the Free Software
 *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
 */

#ifndef __SOUND_PCXHR_H
#define __SOUND_PCXHR_H

#include <linux/interrupt.h>
#include <linux/mutex.h>
#include <sound/pcm.h>
#include "pcxhr_hrtimer.h"

/* Driver version :  2.0.13 */
#define PCXHR_DRIVER_VERSION				0x020013
#define PCXHR_DRIVER_VERSION_STRING	"2.0.13"

/* Workaround for CentOS/RHEL */
#ifdef RHEL_RELEASE_CODE
#  define HAVE_SND_CARD_NEW (RHEL_RELEASE_CODE >= RHEL_RELEASE_VERSION(7,5))
#  define PREALLOCATE_PAGES_FOR_ALL_RETURNS_NO_ERR (RHEL_RELEASE_CODE >= RHEL_RELEASE_VERSION(7,5))
#else
#  define HAVE_SND_CARD_NEW (LINUX_VERSION_CODE >= KERNEL_VERSION(3,15,0))
#  define PREALLOCATE_PAGES_FOR_ALL_RETURNS_NO_ERR (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 0, 0))
#endif

#define PCXHR_MAX_CARDS		6
#define PCXHR_PLAYBACK_STREAMS	4

#define PCXHR_GRANULARITY	96	/* min 96 and multiple of 48 */
/* transfer granularity of pipes and the dsp time (MBOX4) */
#define PCXHR_GRANULARITY_MIN	96
/* TODO : granularity could be 64 or 128 */
#define PCXHR_GRANULARITY_HR22	192	/* granularity for stereo cards */

struct snd_pcxhr;
struct pcxhr_mgr;

struct pcxhr_stream;
struct pcxhr_pipe;

enum pcxhr_clock_type {
	PCXHR_CLOCK_TYPE_INTERNAL = 0,
	PCXHR_CLOCK_TYPE_WORD_CLOCK,
	PCXHR_CLOCK_TYPE_AES_SYNC,
	PCXHR_CLOCK_TYPE_AES_1,
	PCXHR_CLOCK_TYPE_AES_2,
	PCXHR_CLOCK_TYPE_AES_3,
	PCXHR_CLOCK_TYPE_AES_4,
	PCXHR_CLOCK_TYPE_MAX = PCXHR_CLOCK_TYPE_AES_4,
	HR22_CLOCK_TYPE_INTERNAL = PCXHR_CLOCK_TYPE_INTERNAL,
	HR22_CLOCK_TYPE_AES_SYNC,
	HR22_CLOCK_TYPE_AES_1,
	HR22_CLOCK_TYPE_MAX = HR22_CLOCK_TYPE_AES_1,
};

enum pcxhr_board_revision_id{
	PCXHR_BOARD_REVISION_BEFORE_5 = 0,
	PCXHR_BOARD_REVISION_5 = 1,
	PCXHR_BOARD_REVISION_7 = 2,
};

struct pcxhr_dbg_cpt {
	unsigned int interrupts_all;
	unsigned int interrupts_none;
	unsigned int interrupts_handled;
	unsigned int interrupts_dummy;
	unsigned int interrupts_irq;
	unsigned int interrupts_async;
	unsigned int interrupts_incr;
	unsigned int interrupts_loop;
	unsigned int interrupts_false_irq_none;
};

struct pcxhr_mgr {
	unsigned int num_cards;
	struct snd_pcxhr *chip[PCXHR_MAX_CARDS];

	struct pci_dev *pci;

	int irq;

	int granularity;

	/* card access with 1 mem bar and 2 io bar's */
	unsigned long port[3];
	unsigned long dsp_reg_offset;

	/* share the name */
	char shortname[32];		/* short name of this soundcard */
	char longname[96];		/* name of this soundcard */

	/* message tasklet */
	struct tasklet_struct msg_taskq;
	struct pcxhr_rmh *prmh;
	/* trigger tasklet */
	struct tasklet_struct trigger_taskq;

	spinlock_t lock;		/* interrupt spinlock */
	spinlock_t msg_lock;		/* message spinlock */

	struct mutex setup_mutex;	/* mutex used in hw_params, open and close */
	struct mutex mixer_mutex;	/* mutex for mixer */

	/* hardware interface */
	unsigned int dsp_loaded;	/* bit flags of loaded dsp indices */
	unsigned int dsp_version;	/* read from embedded once firmware is loaded */
	int playback_chips;
	int capture_chips;
	int fw_file_set;
	int firmware_num;
	unsigned int is_hr_stereo:1;
	unsigned int board_has_aes1:1;	/* if 1 board has AES1 plug and SRC */
	unsigned int board_has_analog:1; /* if 0 the board is digital only */
	unsigned int board_has_mic:1; /* if 1 the board has microphone input */
	unsigned int board_aes_in_192k:1;/* if 1 the aes input plugs do support 192kHz */
	unsigned int mono_capture:1; /* if 1 the board does mono capture */
	unsigned int capture_ltc:1; /* if 1 the board captures LTC input */

	struct snd_dma_buffer hostport;

	enum pcxhr_clock_type use_clock_type;	/* clock type selected by mixer */
	enum pcxhr_clock_type cur_clock_type;	/* current clock type synced */
	int sample_rate;
	int ref_count_rate;
	int timer_toggle;		/* timer interrupt toggles between the two values 0x200 and 0x300 */
	int dsp_time_last;		/* the last dsp time (read by interrupt) */
	int dsp_time_err;		/* dsp time errors */
	int hr_timer_calls;		/* hrtimer calls */
	unsigned int src_it_dsp;	/* dsp interrupt source */
	unsigned int io_num_reg_cont;	/* backup of IO_NUM_REG_CONT */
	unsigned int codec_speed;	/* speed mode of the codecs */
	unsigned int sample_rate_real;	/* current real sample rate */
	int last_reg_stat;
	int async_err_stream_xrun;
	int async_err_pipe_xrun;
	int async_err_other_last;

	unsigned char xlx_cfg;		/* copy of PCXHR_XLX_CFG register */
	unsigned char xlx_selmic;	/* copy of PCXHR_XLX_SELMIC register */
	unsigned char dsp_reset;	/* copy of PCXHR_DSP_RESET register */

	ktime_t hr_timer_period_time;
	atomic_t hr_timer_running;
	struct hrtimer hr_timer;
	struct tasklet_struct hr_timer_tasklet;

	struct pcxhr_dbg_cpt dbg_cpt;

	enum pcxhr_board_revision_id board_revision; /* Current board revision (IE values)*/
	unsigned int pcm1796_operation_reg_value; /* copy of the operation register (REG 19, @0x13) of the PCM1796*/
};

/* IE support*/
static const unsigned int  PCXHR_DEVICE_IE_ID_MASK = 0x00F0;
static const unsigned int  PCXHR_DEVICE_IE5_ID = 0x0040;
static const unsigned int  PCXHR_DEVICE_IE7_ID = 0x0060;


/* pcxhr_mgr board revision helper */
static inline unsigned int pcxhr_is_board_revision (const struct pcxhr_mgr* toTest, const unsigned int tested_revision)
{
	return toTest->board_revision == tested_revision;
}



enum pcxhr_stream_status {
	PCXHR_STREAM_STATUS_FREE,
	PCXHR_STREAM_STATUS_OPEN,
	PCXHR_STREAM_STATUS_SCHEDULE_RUN,
	PCXHR_STREAM_STATUS_STARTED,
	PCXHR_STREAM_STATUS_RUNNING,
	PCXHR_STREAM_STATUS_SCHEDULE_STOP,
	PCXHR_STREAM_STATUS_STOPPED,
	PCXHR_STREAM_STATUS_PAUSED
};

struct pcxhr_stream {
	struct snd_pcm_substream *substream;
	snd_pcm_format_t format;
	struct pcxhr_pipe *pipe;

	enum pcxhr_stream_status status;	/* free, open, running, draining, pause */

	u_int64_t timer_abs_periods;	/* timer: samples elapsed since TRIGGER_START (multiple of period_size) */
	u_int32_t timer_period_frag;	/* timer: samples elapsed since last call to snd_pcm_period_elapsed (0..period_size) */
	u_int32_t timer_buf_periods;	/* nb of periods in the buffer that have already elapsed */
	int timer_is_synced;		/* if(0) : timer needs to be resynced with real hardware pointer */

	int channels;
};


enum pcxhr_pipe_status {
	PCXHR_PIPE_UNDEFINED,
	PCXHR_PIPE_DEFINED
};

struct pcxhr_pipe {
	enum pcxhr_pipe_status status;
	int is_capture;		/* this is a capture pipe */
	int first_audio;	/* first audio num */
};


struct snd_pcxhr {
	struct snd_card *card;
	struct pcxhr_mgr *mgr;
	int chip_idx;		/* zero based */

	struct snd_pcm *pcm;		/* PCM */

	struct pcxhr_pipe playback_pipe;	/* 1 stereo pipe only */
	struct pcxhr_pipe capture_pipe[2];	/* 1 stereo or 2 mono pipes */

	struct pcxhr_stream playback_stream[PCXHR_PLAYBACK_STREAMS];
	struct pcxhr_stream capture_stream[2];	/* 1 stereo or 2 mono streams */
	int nb_streams_play;
	int nb_streams_capt;

	int analog_playback_active[2];	/* Mixer : Master Playback !mute */
	int analog_playback_volume[2];	/* Mixer : Master Playback Volume */
	int analog_capture_volume[2];	/* Mixer : Master Capture Volume */
	int digital_playback_active[PCXHR_PLAYBACK_STREAMS][2];
	int digital_playback_volume[PCXHR_PLAYBACK_STREAMS][2];
	int digital_capture_volume[2];	/* Mixer : Digital Capture Volume */
	int monitoring_active[2];	/* Mixer : Monitoring Active */
	int monitoring_volume[2];	/* Mixer : Monitoring Volume */
	int audio_capture_source;	/* Mixer : Audio Capture Source */
	int mic_volume;			/* used by cards with MIC only */
	int mic_boost;			/* used by cards with MIC only */
	int mic_active;			/* used by cards with MIC only */
	int analog_capture_active;	/* used by cards with MIC only */
	int phantom_power;		/* used by cards with MIC only */

	unsigned char aes_bits[5];	/* Mixer : IEC958_AES bits */
};

struct pcxhr_hostport
{
	char purgebuffer[6];
	char reserved[2];
};

/* exported */
int pcxhr_create_pcm(struct snd_pcxhr *chip);
int pcxhr_set_clock(struct pcxhr_mgr *mgr, unsigned int rate);
int pcxhr_get_external_clock(struct pcxhr_mgr *mgr,
			     enum pcxhr_clock_type clock_type,
			     int *sample_rate);

/*
 *  @return true if the subsystem_id mathes the given ID mask
 */
static inline unsigned int pcxhr_is_device_IE (unsigned int sub_system_id, const unsigned int proposed_IE)
{
	return ((sub_system_id & PCXHR_DEVICE_IE_ID_MASK) == proposed_IE) ? 1 : 0 ;
}
/*
 *  @return true if the subsystem_id is compatible with the given ID
 */
static inline unsigned int pcxhr_is_device_compatible_IE (unsigned int sub_system_id, const unsigned int proposed_IE)
{
	//Only IE7 is compatible with IE5.
	if (proposed_IE == PCXHR_DEVICE_IE5_ID)
	{
		//Ok for IE >= IE5
		return ((sub_system_id & PCXHR_DEVICE_IE_ID_MASK) >= proposed_IE )? 1 : 0;
	}
	else 
	{
		return pcxhr_is_device_IE(sub_system_id, proposed_IE);
	}
}


#endif /* __SOUND_PCXHR_H */