Blame view

sound/pci/rme32.c 57.1 KB
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
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
  /*
   *   ALSA driver for RME Digi32, Digi32/8 and Digi32 PRO audio interfaces
   *
   *      Copyright (c) 2002-2004 Martin Langer <martin-langer@gmx.de>,
   *                              Pilo Chambert <pilo.c@wanadoo.fr>
   *
   *      Thanks to :        Anders Torger <torger@ludd.luth.se>,
   *                         Henk Hesselink <henk@anda.nl>
   *                         for writing the digi96-driver 
   *                         and RME for all informations.
   *
   *   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., 675 Mass Ave, Cambridge, MA 02139, USA.
   * 
   * 
   * ****************************************************************************
   * 
   * Note #1 "Sek'd models" ................................... martin 2002-12-07
   * 
   * Identical soundcards by Sek'd were labeled:
   * RME Digi 32     = Sek'd Prodif 32
   * RME Digi 32 Pro = Sek'd Prodif 96
   * RME Digi 32/8   = Sek'd Prodif Gold
   * 
   * ****************************************************************************
   * 
   * Note #2 "full duplex mode" ............................... martin 2002-12-07
   * 
   * Full duplex doesn't work. All cards (32, 32/8, 32Pro) are working identical
   * in this mode. Rec data and play data are using the same buffer therefore. At
   * first you have got the playing bits in the buffer and then (after playing
   * them) they were overwitten by the captured sound of the CS8412/14. Both 
   * modes (play/record) are running harmonically hand in hand in the same buffer
   * and you have only one start bit plus one interrupt bit to control this 
   * paired action.
   * This is opposite to the latter rme96 where playing and capturing is totally
   * separated and so their full duplex mode is supported by alsa (using two 
   * start bits and two interrupts for two different buffers). 
   * But due to the wrong sequence of playing and capturing ALSA shows no solved
   * full duplex support for the rme32 at the moment. That's bad, but I'm not
   * able to solve it. Are you motivated enough to solve this problem now? Your
   * patch would be welcome!
   * 
   * ****************************************************************************
   *
   * "The story after the long seeking" -- tiwai
   *
   * Ok, the situation regarding the full duplex is now improved a bit.
   * In the fullduplex mode (given by the module parameter), the hardware buffer
   * is split to halves for read and write directions at the DMA pointer.
   * That is, the half above the current DMA pointer is used for write, and
   * the half below is used for read.  To mangle this strange behavior, an
   * software intermediate buffer is introduced.  This is, of course, not good
   * from the viewpoint of the data transfer efficiency.  However, this allows
   * you to use arbitrary buffer sizes, instead of the fixed I/O buffer size.
   *
   * ****************************************************************************
   */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
70
  #include <linux/delay.h>
5a0e3ad6a   Tejun Heo   include cleanup: ...
71
  #include <linux/gfp.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
72
73
74
  #include <linux/init.h>
  #include <linux/interrupt.h>
  #include <linux/pci.h>
65a772172   Paul Gortmaker   sound: fix driver...
75
  #include <linux/module.h>
6cbbfe1c8   Takashi Iwai   ALSA: Include lin...
76
  #include <linux/io.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
77
78
79
80
81
82
83
84
85
  
  #include <sound/core.h>
  #include <sound/info.h>
  #include <sound/control.h>
  #include <sound/pcm.h>
  #include <sound/pcm_params.h>
  #include <sound/pcm-indirect.h>
  #include <sound/asoundef.h>
  #include <sound/initval.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
86
87
  static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX;	/* Index 0-MAX */
  static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR;	/* ID for this card */
a67ff6a54   Rusty Russell   ALSA: module_para...
88
89
  static bool enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE_PNP;	/* Enable this card */
  static bool fullduplex[SNDRV_CARDS]; // = {[0 ... (SNDRV_CARDS - 1)] = 1};
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
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
  
  module_param_array(index, int, NULL, 0444);
  MODULE_PARM_DESC(index, "Index value for RME Digi32 soundcard.");
  module_param_array(id, charp, NULL, 0444);
  MODULE_PARM_DESC(id, "ID string for RME Digi32 soundcard.");
  module_param_array(enable, bool, NULL, 0444);
  MODULE_PARM_DESC(enable, "Enable RME Digi32 soundcard.");
  module_param_array(fullduplex, bool, NULL, 0444);
  MODULE_PARM_DESC(fullduplex, "Support full-duplex mode.");
  MODULE_AUTHOR("Martin Langer <martin-langer@gmx.de>, Pilo Chambert <pilo.c@wanadoo.fr>");
  MODULE_DESCRIPTION("RME Digi32, Digi32/8, Digi32 PRO");
  MODULE_LICENSE("GPL");
  MODULE_SUPPORTED_DEVICE("{{RME,Digi32}," "{RME,Digi32/8}," "{RME,Digi32 PRO}}");
  
  /* Defines for RME Digi32 series */
  #define RME32_SPDIF_NCHANNELS 2
  
  /* Playback and capture buffer size */
  #define RME32_BUFFER_SIZE 0x20000
  
  /* IO area size */
  #define RME32_IO_SIZE 0x30000
  
  /* IO area offsets */
  #define RME32_IO_DATA_BUFFER        0x0
  #define RME32_IO_CONTROL_REGISTER   0x20000
  #define RME32_IO_GET_POS            0x20000
  #define RME32_IO_CONFIRM_ACTION_IRQ 0x20004
  #define RME32_IO_RESET_POS          0x20100
  
  /* Write control register bits */
  #define RME32_WCR_START     (1 << 0)    /* startbit */
  #define RME32_WCR_MONO      (1 << 1)    /* 0=stereo, 1=mono
                                             Setting the whole card to mono
                                             doesn't seem to be very useful.
                                             A software-solution can handle 
                                             full-duplex with one direction in
                                             stereo and the other way in mono. 
                                             So, the hardware should work all 
                                             the time in stereo! */
  #define RME32_WCR_MODE24    (1 << 2)    /* 0=16bit, 1=32bit */
  #define RME32_WCR_SEL       (1 << 3)    /* 0=input on output, 1=normal playback/capture */
  #define RME32_WCR_FREQ_0    (1 << 4)    /* frequency (play) */
  #define RME32_WCR_FREQ_1    (1 << 5)
  #define RME32_WCR_INP_0     (1 << 6)    /* input switch */
  #define RME32_WCR_INP_1     (1 << 7)
  #define RME32_WCR_RESET     (1 << 8)    /* Reset address */
  #define RME32_WCR_MUTE      (1 << 9)    /* digital mute for output */
  #define RME32_WCR_PRO       (1 << 10)   /* 1=professional, 0=consumer */
  #define RME32_WCR_DS_BM     (1 << 11)	/* 1=DoubleSpeed (only PRO-Version); 1=BlockMode (only Adat-Version) */
  #define RME32_WCR_ADAT      (1 << 12)	/* Adat Mode (only Adat-Version) */
  #define RME32_WCR_AUTOSYNC  (1 << 13)   /* AutoSync */
  #define RME32_WCR_PD        (1 << 14)	/* DAC Reset (only PRO-Version) */
  #define RME32_WCR_EMP       (1 << 15)	/* 1=Emphasis on (only PRO-Version) */
  
  #define RME32_WCR_BITPOS_FREQ_0 4
  #define RME32_WCR_BITPOS_FREQ_1 5
  #define RME32_WCR_BITPOS_INP_0 6
  #define RME32_WCR_BITPOS_INP_1 7
  
  /* Read control register bits */
  #define RME32_RCR_AUDIO_ADDR_MASK 0x1ffff
  #define RME32_RCR_LOCK      (1 << 23)   /* 1=locked, 0=not locked */
  #define RME32_RCR_ERF       (1 << 26)   /* 1=Error, 0=no Error */
  #define RME32_RCR_FREQ_0    (1 << 27)   /* CS841x frequency (record) */
  #define RME32_RCR_FREQ_1    (1 << 28)
  #define RME32_RCR_FREQ_2    (1 << 29)
  #define RME32_RCR_KMODE     (1 << 30)   /* card mode: 1=PLL, 0=quartz */
  #define RME32_RCR_IRQ       (1 << 31)   /* interrupt */
  
  #define RME32_RCR_BITPOS_F0 27
  #define RME32_RCR_BITPOS_F1 28
  #define RME32_RCR_BITPOS_F2 29
  
  /* Input types */
  #define RME32_INPUT_OPTICAL 0
  #define RME32_INPUT_COAXIAL 1
  #define RME32_INPUT_INTERNAL 2
  #define RME32_INPUT_XLR 3
  
  /* Clock modes */
  #define RME32_CLOCKMODE_SLAVE 0
  #define RME32_CLOCKMODE_MASTER_32 1
  #define RME32_CLOCKMODE_MASTER_44 2
  #define RME32_CLOCKMODE_MASTER_48 3
  
  /* Block sizes in bytes */
  #define RME32_BLOCK_SIZE 8192
  
  /* Software intermediate buffer (max) size */
  #define RME32_MID_BUFFER_SIZE (1024*1024)
  
  /* Hardware revisions */
  #define RME32_32_REVISION 192
  #define RME32_328_REVISION_OLD 100
  #define RME32_328_REVISION_NEW 101
  #define RME32_PRO_REVISION_WITH_8412 192
  #define RME32_PRO_REVISION_WITH_8414 150
017ce8023   Takashi Iwai   [ALSA] Remove xxx...
188
  struct rme32 {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
189
190
191
192
193
194
195
196
197
198
199
  	spinlock_t lock;
  	int irq;
  	unsigned long port;
  	void __iomem *iobase;
  
  	u32 wcreg;		/* cached write control register value */
  	u32 wcreg_spdif;	/* S/PDIF setup */
  	u32 wcreg_spdif_stream;	/* S/PDIF setup (temporary) */
  	u32 rcreg;		/* cached read control register value */
  
  	u8 rev;			/* card revision number */
017ce8023   Takashi Iwai   [ALSA] Remove xxx...
200
201
  	struct snd_pcm_substream *playback_substream;
  	struct snd_pcm_substream *capture_substream;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
202
203
204
205
206
207
208
209
210
  
  	int playback_frlog;	/* log2 of framesize */
  	int capture_frlog;
  
  	size_t playback_periodsize;	/* in bytes, zero if not used */
  	size_t capture_periodsize;	/* in bytes, zero if not used */
  
  	unsigned int fullduplex_mode;
  	int running;
017ce8023   Takashi Iwai   [ALSA] Remove xxx...
211
212
  	struct snd_pcm_indirect playback_pcm;
  	struct snd_pcm_indirect capture_pcm;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
213

017ce8023   Takashi Iwai   [ALSA] Remove xxx...
214
215
216
  	struct snd_card *card;
  	struct snd_pcm *spdif_pcm;
  	struct snd_pcm *adat_pcm;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
217
  	struct pci_dev *pci;
017ce8023   Takashi Iwai   [ALSA] Remove xxx...
218
219
  	struct snd_kcontrol *spdif_ctl;
  };
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
220

9baa3c34a   Benoit Taine   PCI: Remove DEFIN...
221
  static const struct pci_device_id snd_rme32_ids[] = {
28d27aae9   Joe Perches   sound: Use PCI_VD...
222
223
224
  	{PCI_VDEVICE(XILINX_RME, PCI_DEVICE_ID_RME_DIGI32), 0,},
  	{PCI_VDEVICE(XILINX_RME, PCI_DEVICE_ID_RME_DIGI32_8), 0,},
  	{PCI_VDEVICE(XILINX_RME, PCI_DEVICE_ID_RME_DIGI32_PRO), 0,},
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
225
226
227
228
229
230
  	{0,}
  };
  
  MODULE_DEVICE_TABLE(pci, snd_rme32_ids);
  
  #define RME32_ISWORKING(rme32) ((rme32)->wcreg & RME32_WCR_START)
8b7fc4214   Roland Dreier   [PATCH] add PCI I...
231
  #define RME32_PRO_WITH_8414(rme32) ((rme32)->pci->device == PCI_DEVICE_ID_RME_DIGI32_PRO && (rme32)->rev == RME32_PRO_REVISION_WITH_8414)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
232

017ce8023   Takashi Iwai   [ALSA] Remove xxx...
233
  static int snd_rme32_playback_prepare(struct snd_pcm_substream *substream);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
234

017ce8023   Takashi Iwai   [ALSA] Remove xxx...
235
  static int snd_rme32_capture_prepare(struct snd_pcm_substream *substream);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
236

017ce8023   Takashi Iwai   [ALSA] Remove xxx...
237
  static int snd_rme32_pcm_trigger(struct snd_pcm_substream *substream, int cmd);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
238

017ce8023   Takashi Iwai   [ALSA] Remove xxx...
239
  static void snd_rme32_proc_init(struct rme32 * rme32);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
240

017ce8023   Takashi Iwai   [ALSA] Remove xxx...
241
  static int snd_rme32_create_switches(struct snd_card *card, struct rme32 * rme32);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
242

017ce8023   Takashi Iwai   [ALSA] Remove xxx...
243
  static inline unsigned int snd_rme32_pcm_byteptr(struct rme32 * rme32)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
244
245
246
247
  {
  	return (readl(rme32->iobase + RME32_IO_GET_POS)
  		& RME32_RCR_AUDIO_ADDR_MASK);
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
248
  /* silence callback for halfduplex mode */
017ce8023   Takashi Iwai   [ALSA] Remove xxx...
249
  static int snd_rme32_playback_silence(struct snd_pcm_substream *substream, int channel,	/* not used (interleaved data) */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
250
251
252
  				      snd_pcm_uframes_t pos,
  				      snd_pcm_uframes_t count)
  {
017ce8023   Takashi Iwai   [ALSA] Remove xxx...
253
  	struct rme32 *rme32 = snd_pcm_substream_chip(substream);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
254
255
256
257
258
259
260
  	count <<= rme32->playback_frlog;
  	pos <<= rme32->playback_frlog;
  	memset_io(rme32->iobase + RME32_IO_DATA_BUFFER + pos, 0, count);
  	return 0;
  }
  
  /* copy callback for halfduplex mode */
017ce8023   Takashi Iwai   [ALSA] Remove xxx...
261
  static int snd_rme32_playback_copy(struct snd_pcm_substream *substream, int channel,	/* not used (interleaved data) */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
262
263
264
  				   snd_pcm_uframes_t pos,
  				   void __user *src, snd_pcm_uframes_t count)
  {
017ce8023   Takashi Iwai   [ALSA] Remove xxx...
265
  	struct rme32 *rme32 = snd_pcm_substream_chip(substream);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
266
267
268
269
270
271
272
273
274
  	count <<= rme32->playback_frlog;
  	pos <<= rme32->playback_frlog;
  	if (copy_from_user_toio(rme32->iobase + RME32_IO_DATA_BUFFER + pos,
  			    src, count))
  		return -EFAULT;
  	return 0;
  }
  
  /* copy callback for halfduplex mode */
017ce8023   Takashi Iwai   [ALSA] Remove xxx...
275
  static int snd_rme32_capture_copy(struct snd_pcm_substream *substream, int channel,	/* not used (interleaved data) */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
276
277
278
  				  snd_pcm_uframes_t pos,
  				  void __user *dst, snd_pcm_uframes_t count)
  {
017ce8023   Takashi Iwai   [ALSA] Remove xxx...
279
  	struct rme32 *rme32 = snd_pcm_substream_chip(substream);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
280
281
282
283
284
285
286
287
288
289
  	count <<= rme32->capture_frlog;
  	pos <<= rme32->capture_frlog;
  	if (copy_to_user_fromio(dst,
  			    rme32->iobase + RME32_IO_DATA_BUFFER + pos,
  			    count))
  		return -EFAULT;
  	return 0;
  }
  
  /*
7f927fcc2   Alexey Dobriyan   [PATCH] Typo fixes
290
   * SPDIF I/O capabilities (half-duplex mode)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
291
   */
017ce8023   Takashi Iwai   [ALSA] Remove xxx...
292
  static struct snd_pcm_hardware snd_rme32_spdif_info = {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
  	.info =		(SNDRV_PCM_INFO_MMAP_IOMEM |
  			 SNDRV_PCM_INFO_MMAP_VALID |
  			 SNDRV_PCM_INFO_INTERLEAVED | 
  			 SNDRV_PCM_INFO_PAUSE |
  			 SNDRV_PCM_INFO_SYNC_START),
  	.formats =	(SNDRV_PCM_FMTBIT_S16_LE | 
  			 SNDRV_PCM_FMTBIT_S32_LE),
  	.rates =	(SNDRV_PCM_RATE_32000 |
  			 SNDRV_PCM_RATE_44100 | 
  			 SNDRV_PCM_RATE_48000),
  	.rate_min =	32000,
  	.rate_max =	48000,
  	.channels_min =	2,
  	.channels_max =	2,
  	.buffer_bytes_max = RME32_BUFFER_SIZE,
  	.period_bytes_min = RME32_BLOCK_SIZE,
  	.period_bytes_max = RME32_BLOCK_SIZE,
  	.periods_min =	RME32_BUFFER_SIZE / RME32_BLOCK_SIZE,
  	.periods_max =	RME32_BUFFER_SIZE / RME32_BLOCK_SIZE,
  	.fifo_size =	0,
  };
  
  /*
7f927fcc2   Alexey Dobriyan   [PATCH] Typo fixes
316
   * ADAT I/O capabilities (half-duplex mode)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
317
   */
017ce8023   Takashi Iwai   [ALSA] Remove xxx...
318
  static struct snd_pcm_hardware snd_rme32_adat_info =
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
  {
  	.info =		     (SNDRV_PCM_INFO_MMAP_IOMEM |
  			      SNDRV_PCM_INFO_MMAP_VALID |
  			      SNDRV_PCM_INFO_INTERLEAVED |
  			      SNDRV_PCM_INFO_PAUSE |
  			      SNDRV_PCM_INFO_SYNC_START),
  	.formats=            SNDRV_PCM_FMTBIT_S16_LE,
  	.rates =             (SNDRV_PCM_RATE_44100 | 
  			      SNDRV_PCM_RATE_48000),
  	.rate_min =          44100,
  	.rate_max =          48000,
  	.channels_min =      8,
  	.channels_max =	     8,
  	.buffer_bytes_max =  RME32_BUFFER_SIZE,
  	.period_bytes_min =  RME32_BLOCK_SIZE,
  	.period_bytes_max =  RME32_BLOCK_SIZE,
  	.periods_min =	    RME32_BUFFER_SIZE / RME32_BLOCK_SIZE,
  	.periods_max =	    RME32_BUFFER_SIZE / RME32_BLOCK_SIZE,
  	.fifo_size =	    0,
  };
  
  /*
7f927fcc2   Alexey Dobriyan   [PATCH] Typo fixes
341
   * SPDIF I/O capabilities (full-duplex mode)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
342
   */
017ce8023   Takashi Iwai   [ALSA] Remove xxx...
343
  static struct snd_pcm_hardware snd_rme32_spdif_fd_info = {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
  	.info =		(SNDRV_PCM_INFO_MMAP |
  			 SNDRV_PCM_INFO_MMAP_VALID |
  			 SNDRV_PCM_INFO_INTERLEAVED | 
  			 SNDRV_PCM_INFO_PAUSE |
  			 SNDRV_PCM_INFO_SYNC_START),
  	.formats =	(SNDRV_PCM_FMTBIT_S16_LE | 
  			 SNDRV_PCM_FMTBIT_S32_LE),
  	.rates =	(SNDRV_PCM_RATE_32000 |
  			 SNDRV_PCM_RATE_44100 | 
  			 SNDRV_PCM_RATE_48000),
  	.rate_min =	32000,
  	.rate_max =	48000,
  	.channels_min =	2,
  	.channels_max =	2,
  	.buffer_bytes_max = RME32_MID_BUFFER_SIZE,
  	.period_bytes_min = RME32_BLOCK_SIZE,
  	.period_bytes_max = RME32_BLOCK_SIZE,
  	.periods_min =	2,
  	.periods_max =	RME32_MID_BUFFER_SIZE / RME32_BLOCK_SIZE,
  	.fifo_size =	0,
  };
  
  /*
7f927fcc2   Alexey Dobriyan   [PATCH] Typo fixes
367
   * ADAT I/O capabilities (full-duplex mode)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
368
   */
017ce8023   Takashi Iwai   [ALSA] Remove xxx...
369
  static struct snd_pcm_hardware snd_rme32_adat_fd_info =
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
  {
  	.info =		     (SNDRV_PCM_INFO_MMAP |
  			      SNDRV_PCM_INFO_MMAP_VALID |
  			      SNDRV_PCM_INFO_INTERLEAVED |
  			      SNDRV_PCM_INFO_PAUSE |
  			      SNDRV_PCM_INFO_SYNC_START),
  	.formats=            SNDRV_PCM_FMTBIT_S16_LE,
  	.rates =             (SNDRV_PCM_RATE_44100 | 
  			      SNDRV_PCM_RATE_48000),
  	.rate_min =          44100,
  	.rate_max =          48000,
  	.channels_min =      8,
  	.channels_max =	     8,
  	.buffer_bytes_max =  RME32_MID_BUFFER_SIZE,
  	.period_bytes_min =  RME32_BLOCK_SIZE,
  	.period_bytes_max =  RME32_BLOCK_SIZE,
  	.periods_min =	    2,
  	.periods_max =	    RME32_MID_BUFFER_SIZE / RME32_BLOCK_SIZE,
  	.fifo_size =	    0,
  };
017ce8023   Takashi Iwai   [ALSA] Remove xxx...
390
  static void snd_rme32_reset_dac(struct rme32 *rme32)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
391
392
393
394
395
  {
          writel(rme32->wcreg | RME32_WCR_PD,
                 rme32->iobase + RME32_IO_CONTROL_REGISTER);
          writel(rme32->wcreg, rme32->iobase + RME32_IO_CONTROL_REGISTER);
  }
017ce8023   Takashi Iwai   [ALSA] Remove xxx...
396
  static int snd_rme32_playback_getrate(struct rme32 * rme32)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
  {
  	int rate;
  
  	rate = ((rme32->wcreg >> RME32_WCR_BITPOS_FREQ_0) & 1) +
  	       (((rme32->wcreg >> RME32_WCR_BITPOS_FREQ_1) & 1) << 1);
  	switch (rate) {
  	case 1:
  		rate = 32000;
  		break;
  	case 2:
  		rate = 44100;
  		break;
  	case 3:
  		rate = 48000;
  		break;
  	default:
  		return -1;
  	}
  	return (rme32->wcreg & RME32_WCR_DS_BM) ? rate << 1 : rate;
  }
017ce8023   Takashi Iwai   [ALSA] Remove xxx...
417
  static int snd_rme32_capture_getrate(struct rme32 * rme32, int *is_adat)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
  {
  	int n;
  
  	*is_adat = 0;
  	if (rme32->rcreg & RME32_RCR_LOCK) { 
                  /* ADAT rate */
                  *is_adat = 1;
  	}
  	if (rme32->rcreg & RME32_RCR_ERF) {
  		return -1;
  	}
  
          /* S/PDIF rate */
  	n = ((rme32->rcreg >> RME32_RCR_BITPOS_F0) & 1) +
  		(((rme32->rcreg >> RME32_RCR_BITPOS_F1) & 1) << 1) +
  		(((rme32->rcreg >> RME32_RCR_BITPOS_F2) & 1) << 2);
  
  	if (RME32_PRO_WITH_8414(rme32))
  		switch (n) {	/* supporting the CS8414 */
  		case 0:
  		case 1:
  		case 2:
  			return -1;
  		case 3:
  			return 96000;
  		case 4:
  			return 88200;
  		case 5:
  			return 48000;
  		case 6:
  			return 44100;
  		case 7:
  			return 32000;
  		default:
  			return -1;
  			break;
  		} 
  	else
  		switch (n) {	/* supporting the CS8412 */
  		case 0:
  			return -1;
  		case 1:
  			return 48000;
  		case 2:
  			return 44100;
  		case 3:
  			return 32000;
  		case 4:
  			return 48000;
  		case 5:
  			return 44100;
  		case 6:
  			return 44056;
  		case 7:
  			return 32000;
  		default:
  			break;
  		}
  	return -1;
  }
017ce8023   Takashi Iwai   [ALSA] Remove xxx...
478
  static int snd_rme32_playback_setrate(struct rme32 * rme32, int rate)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
  {
          int ds;
  
          ds = rme32->wcreg & RME32_WCR_DS_BM;
  	switch (rate) {
  	case 32000:
  		rme32->wcreg &= ~RME32_WCR_DS_BM;
  		rme32->wcreg = (rme32->wcreg | RME32_WCR_FREQ_0) & 
  			~RME32_WCR_FREQ_1;
  		break;
  	case 44100:
  		rme32->wcreg &= ~RME32_WCR_DS_BM;
  		rme32->wcreg = (rme32->wcreg | RME32_WCR_FREQ_1) & 
  			~RME32_WCR_FREQ_0;
  		break;
  	case 48000:
  		rme32->wcreg &= ~RME32_WCR_DS_BM;
  		rme32->wcreg = (rme32->wcreg | RME32_WCR_FREQ_0) | 
  			RME32_WCR_FREQ_1;
  		break;
  	case 64000:
8b7fc4214   Roland Dreier   [PATCH] add PCI I...
500
  		if (rme32->pci->device != PCI_DEVICE_ID_RME_DIGI32_PRO)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
501
502
503
504
505
506
  			return -EINVAL;
  		rme32->wcreg |= RME32_WCR_DS_BM;
  		rme32->wcreg = (rme32->wcreg | RME32_WCR_FREQ_0) & 
  			~RME32_WCR_FREQ_1;
  		break;
  	case 88200:
8b7fc4214   Roland Dreier   [PATCH] add PCI I...
507
  		if (rme32->pci->device != PCI_DEVICE_ID_RME_DIGI32_PRO)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
508
509
510
511
512
513
  			return -EINVAL;
  		rme32->wcreg |= RME32_WCR_DS_BM;
  		rme32->wcreg = (rme32->wcreg | RME32_WCR_FREQ_1) & 
  			~RME32_WCR_FREQ_0;
  		break;
  	case 96000:
8b7fc4214   Roland Dreier   [PATCH] add PCI I...
514
  		if (rme32->pci->device != PCI_DEVICE_ID_RME_DIGI32_PRO)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
  			return -EINVAL;
  		rme32->wcreg |= RME32_WCR_DS_BM;
  		rme32->wcreg = (rme32->wcreg | RME32_WCR_FREQ_0) | 
  			RME32_WCR_FREQ_1;
  		break;
  	default:
  		return -EINVAL;
  	}
          if ((!ds && rme32->wcreg & RME32_WCR_DS_BM) ||
              (ds && !(rme32->wcreg & RME32_WCR_DS_BM)))
          {
                  /* change to/from double-speed: reset the DAC (if available) */
                  snd_rme32_reset_dac(rme32);
          } else {
                  writel(rme32->wcreg, rme32->iobase + RME32_IO_CONTROL_REGISTER);
  	}
  	return 0;
  }
017ce8023   Takashi Iwai   [ALSA] Remove xxx...
533
  static int snd_rme32_setclockmode(struct rme32 * rme32, int mode)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
  {
  	switch (mode) {
  	case RME32_CLOCKMODE_SLAVE:
  		/* AutoSync */
  		rme32->wcreg = (rme32->wcreg & ~RME32_WCR_FREQ_0) & 
  			~RME32_WCR_FREQ_1;
  		break;
  	case RME32_CLOCKMODE_MASTER_32:
  		/* Internal 32.0kHz */
  		rme32->wcreg = (rme32->wcreg | RME32_WCR_FREQ_0) & 
  			~RME32_WCR_FREQ_1;
  		break;
  	case RME32_CLOCKMODE_MASTER_44:
  		/* Internal 44.1kHz */
  		rme32->wcreg = (rme32->wcreg & ~RME32_WCR_FREQ_0) | 
  			RME32_WCR_FREQ_1;
  		break;
  	case RME32_CLOCKMODE_MASTER_48:
  		/* Internal 48.0kHz */
  		rme32->wcreg = (rme32->wcreg | RME32_WCR_FREQ_0) | 
  			RME32_WCR_FREQ_1;
  		break;
  	default:
  		return -EINVAL;
  	}
  	writel(rme32->wcreg, rme32->iobase + RME32_IO_CONTROL_REGISTER);
  	return 0;
  }
017ce8023   Takashi Iwai   [ALSA] Remove xxx...
562
  static int snd_rme32_getclockmode(struct rme32 * rme32)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
563
564
565
566
  {
  	return ((rme32->wcreg >> RME32_WCR_BITPOS_FREQ_0) & 1) +
  	    (((rme32->wcreg >> RME32_WCR_BITPOS_FREQ_1) & 1) << 1);
  }
017ce8023   Takashi Iwai   [ALSA] Remove xxx...
567
  static int snd_rme32_setinputtype(struct rme32 * rme32, int type)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
  {
  	switch (type) {
  	case RME32_INPUT_OPTICAL:
  		rme32->wcreg = (rme32->wcreg & ~RME32_WCR_INP_0) & 
  			~RME32_WCR_INP_1;
  		break;
  	case RME32_INPUT_COAXIAL:
  		rme32->wcreg = (rme32->wcreg | RME32_WCR_INP_0) & 
  			~RME32_WCR_INP_1;
  		break;
  	case RME32_INPUT_INTERNAL:
  		rme32->wcreg = (rme32->wcreg & ~RME32_WCR_INP_0) | 
  			RME32_WCR_INP_1;
  		break;
  	case RME32_INPUT_XLR:
  		rme32->wcreg = (rme32->wcreg | RME32_WCR_INP_0) | 
  			RME32_WCR_INP_1;
  		break;
  	default:
  		return -EINVAL;
  	}
  	writel(rme32->wcreg, rme32->iobase + RME32_IO_CONTROL_REGISTER);
  	return 0;
  }
017ce8023   Takashi Iwai   [ALSA] Remove xxx...
592
  static int snd_rme32_getinputtype(struct rme32 * rme32)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
593
594
595
596
597
598
  {
  	return ((rme32->wcreg >> RME32_WCR_BITPOS_INP_0) & 1) +
  	    (((rme32->wcreg >> RME32_WCR_BITPOS_INP_1) & 1) << 1);
  }
  
  static void
017ce8023   Takashi Iwai   [ALSA] Remove xxx...
599
  snd_rme32_setframelog(struct rme32 * rme32, int n_channels, int is_playback)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
  {
  	int frlog;
  
  	if (n_channels == 2) {
  		frlog = 1;
  	} else {
  		/* assume 8 channels */
  		frlog = 3;
  	}
  	if (is_playback) {
  		frlog += (rme32->wcreg & RME32_WCR_MODE24) ? 2 : 1;
  		rme32->playback_frlog = frlog;
  	} else {
  		frlog += (rme32->wcreg & RME32_WCR_MODE24) ? 2 : 1;
  		rme32->capture_frlog = frlog;
  	}
  }
6c869d301   Takashi Iwai   ALSA: rme*: Use s...
617
  static int snd_rme32_setformat(struct rme32 *rme32, snd_pcm_format_t format)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
  {
  	switch (format) {
  	case SNDRV_PCM_FORMAT_S16_LE:
  		rme32->wcreg &= ~RME32_WCR_MODE24;
  		break;
  	case SNDRV_PCM_FORMAT_S32_LE:
  		rme32->wcreg |= RME32_WCR_MODE24;
  		break;
  	default:
  		return -EINVAL;
  	}
  	writel(rme32->wcreg, rme32->iobase + RME32_IO_CONTROL_REGISTER);
  	return 0;
  }
  
  static int
017ce8023   Takashi Iwai   [ALSA] Remove xxx...
634
635
  snd_rme32_playback_hw_params(struct snd_pcm_substream *substream,
  			     struct snd_pcm_hw_params *params)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
636
637
  {
  	int err, rate, dummy;
017ce8023   Takashi Iwai   [ALSA] Remove xxx...
638
639
  	struct rme32 *rme32 = snd_pcm_substream_chip(substream);
  	struct snd_pcm_runtime *runtime = substream->runtime;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
640
641
642
643
644
645
  
  	if (rme32->fullduplex_mode) {
  		err = snd_pcm_lib_malloc_pages(substream, params_buffer_bytes(params));
  		if (err < 0)
  			return err;
  	} else {
4d23359b7   Clemens Ladisch   [ALSA] sparse add...
646
647
  		runtime->dma_area = (void __force *)(rme32->iobase +
  						     RME32_IO_DATA_BUFFER);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
  		runtime->dma_addr = rme32->port + RME32_IO_DATA_BUFFER;
  		runtime->dma_bytes = RME32_BUFFER_SIZE;
  	}
  
  	spin_lock_irq(&rme32->lock);
  	if ((rme32->rcreg & RME32_RCR_KMODE) &&
  	    (rate = snd_rme32_capture_getrate(rme32, &dummy)) > 0) {
  		/* AutoSync */
  		if ((int)params_rate(params) != rate) {
  			spin_unlock_irq(&rme32->lock);
  			return -EIO;
  		}
  	} else if ((err = snd_rme32_playback_setrate(rme32, params_rate(params))) < 0) {
  		spin_unlock_irq(&rme32->lock);
  		return err;
  	}
  	if ((err = snd_rme32_setformat(rme32, params_format(params))) < 0) {
  		spin_unlock_irq(&rme32->lock);
  		return err;
  	}
  
  	snd_rme32_setframelog(rme32, params_channels(params), 1);
  	if (rme32->capture_periodsize != 0) {
  		if (params_period_size(params) << rme32->playback_frlog != rme32->capture_periodsize) {
  			spin_unlock_irq(&rme32->lock);
  			return -EBUSY;
  		}
  	}
  	rme32->playback_periodsize = params_period_size(params) << rme32->playback_frlog;
  	/* S/PDIF setup */
  	if ((rme32->wcreg & RME32_WCR_ADAT) == 0) {
  		rme32->wcreg &= ~(RME32_WCR_PRO | RME32_WCR_EMP);
  		rme32->wcreg |= rme32->wcreg_spdif_stream;
  		writel(rme32->wcreg, rme32->iobase + RME32_IO_CONTROL_REGISTER);
  	}
  	spin_unlock_irq(&rme32->lock);
  
  	return 0;
  }
  
  static int
017ce8023   Takashi Iwai   [ALSA] Remove xxx...
689
690
  snd_rme32_capture_hw_params(struct snd_pcm_substream *substream,
  			    struct snd_pcm_hw_params *params)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
691
692
  {
  	int err, isadat, rate;
017ce8023   Takashi Iwai   [ALSA] Remove xxx...
693
694
  	struct rme32 *rme32 = snd_pcm_substream_chip(substream);
  	struct snd_pcm_runtime *runtime = substream->runtime;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
695
696
697
698
699
700
  
  	if (rme32->fullduplex_mode) {
  		err = snd_pcm_lib_malloc_pages(substream, params_buffer_bytes(params));
  		if (err < 0)
  			return err;
  	} else {
4d23359b7   Clemens Ladisch   [ALSA] sparse add...
701
702
  		runtime->dma_area = (void __force *)rme32->iobase +
  					RME32_IO_DATA_BUFFER;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
  		runtime->dma_addr = rme32->port + RME32_IO_DATA_BUFFER;
  		runtime->dma_bytes = RME32_BUFFER_SIZE;
  	}
  
  	spin_lock_irq(&rme32->lock);
  	/* enable AutoSync for record-preparing */
  	rme32->wcreg |= RME32_WCR_AUTOSYNC;
  	writel(rme32->wcreg, rme32->iobase + RME32_IO_CONTROL_REGISTER);
  
  	if ((err = snd_rme32_setformat(rme32, params_format(params))) < 0) {
  		spin_unlock_irq(&rme32->lock);
  		return err;
  	}
  	if ((err = snd_rme32_playback_setrate(rme32, params_rate(params))) < 0) {
  		spin_unlock_irq(&rme32->lock);
  		return err;
  	}
  	if ((rate = snd_rme32_capture_getrate(rme32, &isadat)) > 0) {
                  if ((int)params_rate(params) != rate) {
  			spin_unlock_irq(&rme32->lock);
                          return -EIO;                    
                  }
                  if ((isadat && runtime->hw.channels_min == 2) ||
                      (!isadat && runtime->hw.channels_min == 8)) {
  			spin_unlock_irq(&rme32->lock);
                          return -EIO;
                  }
  	}
  	/* AutoSync off for recording */
  	rme32->wcreg &= ~RME32_WCR_AUTOSYNC;
  	writel(rme32->wcreg, rme32->iobase + RME32_IO_CONTROL_REGISTER);
  
  	snd_rme32_setframelog(rme32, params_channels(params), 0);
  	if (rme32->playback_periodsize != 0) {
  		if (params_period_size(params) << rme32->capture_frlog !=
  		    rme32->playback_periodsize) {
  			spin_unlock_irq(&rme32->lock);
  			return -EBUSY;
  		}
  	}
  	rme32->capture_periodsize =
  	    params_period_size(params) << rme32->capture_frlog;
  	spin_unlock_irq(&rme32->lock);
  
  	return 0;
  }
017ce8023   Takashi Iwai   [ALSA] Remove xxx...
749
  static int snd_rme32_pcm_hw_free(struct snd_pcm_substream *substream)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
750
  {
017ce8023   Takashi Iwai   [ALSA] Remove xxx...
751
  	struct rme32 *rme32 = snd_pcm_substream_chip(substream);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
752
753
754
755
  	if (! rme32->fullduplex_mode)
  		return 0;
  	return snd_pcm_lib_free_pages(substream);
  }
017ce8023   Takashi Iwai   [ALSA] Remove xxx...
756
  static void snd_rme32_pcm_start(struct rme32 * rme32, int from_pause)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
757
758
759
760
761
762
763
764
  {
  	if (!from_pause) {
  		writel(0, rme32->iobase + RME32_IO_RESET_POS);
  	}
  
  	rme32->wcreg |= RME32_WCR_START;
  	writel(rme32->wcreg, rme32->iobase + RME32_IO_CONTROL_REGISTER);
  }
017ce8023   Takashi Iwai   [ALSA] Remove xxx...
765
  static void snd_rme32_pcm_stop(struct rme32 * rme32, int to_pause)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
  {
  	/*
  	 * Check if there is an unconfirmed IRQ, if so confirm it, or else
  	 * the hardware will not stop generating interrupts
  	 */
  	rme32->rcreg = readl(rme32->iobase + RME32_IO_CONTROL_REGISTER);
  	if (rme32->rcreg & RME32_RCR_IRQ) {
  		writel(0, rme32->iobase + RME32_IO_CONFIRM_ACTION_IRQ);
  	}
  	rme32->wcreg &= ~RME32_WCR_START;
  	if (rme32->wcreg & RME32_WCR_SEL)
  		rme32->wcreg |= RME32_WCR_MUTE;
  	writel(rme32->wcreg, rme32->iobase + RME32_IO_CONTROL_REGISTER);
  	if (! to_pause)
  		writel(0, rme32->iobase + RME32_IO_RESET_POS);
  }
7d12e780e   David Howells   IRQ: Maintain reg...
782
  static irqreturn_t snd_rme32_interrupt(int irq, void *dev_id)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
783
  {
017ce8023   Takashi Iwai   [ALSA] Remove xxx...
784
  	struct rme32 *rme32 = (struct rme32 *) dev_id;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
  
  	rme32->rcreg = readl(rme32->iobase + RME32_IO_CONTROL_REGISTER);
  	if (!(rme32->rcreg & RME32_RCR_IRQ)) {
  		return IRQ_NONE;
  	} else {
  		if (rme32->capture_substream) {
  			snd_pcm_period_elapsed(rme32->capture_substream);
  		}
  		if (rme32->playback_substream) {
  			snd_pcm_period_elapsed(rme32->playback_substream);
  		}
  		writel(0, rme32->iobase + RME32_IO_CONFIRM_ACTION_IRQ);
  	}
  	return IRQ_HANDLED;
  }
  
  static unsigned int period_bytes[] = { RME32_BLOCK_SIZE };
017ce8023   Takashi Iwai   [ALSA] Remove xxx...
802
  static struct snd_pcm_hw_constraint_list hw_constraints_period_bytes = {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
803
804
805
806
  	.count = ARRAY_SIZE(period_bytes),
  	.list = period_bytes,
  	.mask = 0
  };
017ce8023   Takashi Iwai   [ALSA] Remove xxx...
807
  static void snd_rme32_set_buffer_constraint(struct rme32 *rme32, struct snd_pcm_runtime *runtime)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
808
809
810
811
812
813
814
815
816
817
  {
  	if (! rme32->fullduplex_mode) {
  		snd_pcm_hw_constraint_minmax(runtime,
  					     SNDRV_PCM_HW_PARAM_BUFFER_BYTES,
  					     RME32_BUFFER_SIZE, RME32_BUFFER_SIZE);
  		snd_pcm_hw_constraint_list(runtime, 0,
  					   SNDRV_PCM_HW_PARAM_PERIOD_BYTES,
  					   &hw_constraints_period_bytes);
  	}
  }
017ce8023   Takashi Iwai   [ALSA] Remove xxx...
818
  static int snd_rme32_playback_spdif_open(struct snd_pcm_substream *substream)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
819
820
  {
  	int rate, dummy;
017ce8023   Takashi Iwai   [ALSA] Remove xxx...
821
822
  	struct rme32 *rme32 = snd_pcm_substream_chip(substream);
  	struct snd_pcm_runtime *runtime = substream->runtime;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
  
  	snd_pcm_set_sync(substream);
  
  	spin_lock_irq(&rme32->lock);
  	if (rme32->playback_substream != NULL) {
  		spin_unlock_irq(&rme32->lock);
  		return -EBUSY;
  	}
  	rme32->wcreg &= ~RME32_WCR_ADAT;
  	writel(rme32->wcreg, rme32->iobase + RME32_IO_CONTROL_REGISTER);
  	rme32->playback_substream = substream;
  	spin_unlock_irq(&rme32->lock);
  
  	if (rme32->fullduplex_mode)
  		runtime->hw = snd_rme32_spdif_fd_info;
  	else
  		runtime->hw = snd_rme32_spdif_info;
8b7fc4214   Roland Dreier   [PATCH] add PCI I...
840
  	if (rme32->pci->device == PCI_DEVICE_ID_RME_DIGI32_PRO) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
841
842
843
844
845
846
  		runtime->hw.rates |= SNDRV_PCM_RATE_64000 | SNDRV_PCM_RATE_88200 | SNDRV_PCM_RATE_96000;
  		runtime->hw.rate_max = 96000;
  	}
  	if ((rme32->rcreg & RME32_RCR_KMODE) &&
  	    (rate = snd_rme32_capture_getrate(rme32, &dummy)) > 0) {
  		/* AutoSync */
918f3a0e8   Clemens Ladisch   [ALSA] pcm: add s...
847
  		runtime->hw.rates = snd_pcm_rate_to_rate_bit(rate);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
848
849
850
851
852
853
854
855
856
857
858
859
  		runtime->hw.rate_min = rate;
  		runtime->hw.rate_max = rate;
  	}       
  
  	snd_rme32_set_buffer_constraint(rme32, runtime);
  
  	rme32->wcreg_spdif_stream = rme32->wcreg_spdif;
  	rme32->spdif_ctl->vd[0].access &= ~SNDRV_CTL_ELEM_ACCESS_INACTIVE;
  	snd_ctl_notify(rme32->card, SNDRV_CTL_EVENT_MASK_VALUE |
  		       SNDRV_CTL_EVENT_MASK_INFO, &rme32->spdif_ctl->id);
  	return 0;
  }
017ce8023   Takashi Iwai   [ALSA] Remove xxx...
860
  static int snd_rme32_capture_spdif_open(struct snd_pcm_substream *substream)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
861
862
  {
  	int isadat, rate;
017ce8023   Takashi Iwai   [ALSA] Remove xxx...
863
864
  	struct rme32 *rme32 = snd_pcm_substream_chip(substream);
  	struct snd_pcm_runtime *runtime = substream->runtime;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
  
  	snd_pcm_set_sync(substream);
  
  	spin_lock_irq(&rme32->lock);
          if (rme32->capture_substream != NULL) {
  		spin_unlock_irq(&rme32->lock);
                  return -EBUSY;
          }
  	rme32->capture_substream = substream;
  	spin_unlock_irq(&rme32->lock);
  
  	if (rme32->fullduplex_mode)
  		runtime->hw = snd_rme32_spdif_fd_info;
  	else
  		runtime->hw = snd_rme32_spdif_info;
  	if (RME32_PRO_WITH_8414(rme32)) {
  		runtime->hw.rates |= SNDRV_PCM_RATE_88200 | SNDRV_PCM_RATE_96000;
  		runtime->hw.rate_max = 96000;
  	}
  	if ((rate = snd_rme32_capture_getrate(rme32, &isadat)) > 0) {
  		if (isadat) {
  			return -EIO;
  		}
918f3a0e8   Clemens Ladisch   [ALSA] pcm: add s...
888
  		runtime->hw.rates = snd_pcm_rate_to_rate_bit(rate);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
889
890
891
892
893
894
895
896
897
898
  		runtime->hw.rate_min = rate;
  		runtime->hw.rate_max = rate;
  	}
  
  	snd_rme32_set_buffer_constraint(rme32, runtime);
  
  	return 0;
  }
  
  static int
017ce8023   Takashi Iwai   [ALSA] Remove xxx...
899
  snd_rme32_playback_adat_open(struct snd_pcm_substream *substream)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
900
901
  {
  	int rate, dummy;
017ce8023   Takashi Iwai   [ALSA] Remove xxx...
902
903
  	struct rme32 *rme32 = snd_pcm_substream_chip(substream);
  	struct snd_pcm_runtime *runtime = substream->runtime;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
  	
  	snd_pcm_set_sync(substream);
  
  	spin_lock_irq(&rme32->lock);	
          if (rme32->playback_substream != NULL) {
  		spin_unlock_irq(&rme32->lock);
                  return -EBUSY;
          }
  	rme32->wcreg |= RME32_WCR_ADAT;
  	writel(rme32->wcreg, rme32->iobase + RME32_IO_CONTROL_REGISTER);
  	rme32->playback_substream = substream;
  	spin_unlock_irq(&rme32->lock);
  	
  	if (rme32->fullduplex_mode)
  		runtime->hw = snd_rme32_adat_fd_info;
  	else
  		runtime->hw = snd_rme32_adat_info;
  	if ((rme32->rcreg & RME32_RCR_KMODE) &&
  	    (rate = snd_rme32_capture_getrate(rme32, &dummy)) > 0) {
                  /* AutoSync */
918f3a0e8   Clemens Ladisch   [ALSA] pcm: add s...
924
                  runtime->hw.rates = snd_pcm_rate_to_rate_bit(rate);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
925
926
927
928
929
930
931
932
933
                  runtime->hw.rate_min = rate;
                  runtime->hw.rate_max = rate;
  	}        
  
  	snd_rme32_set_buffer_constraint(rme32, runtime);
  	return 0;
  }
  
  static int
017ce8023   Takashi Iwai   [ALSA] Remove xxx...
934
  snd_rme32_capture_adat_open(struct snd_pcm_substream *substream)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
935
936
  {
  	int isadat, rate;
017ce8023   Takashi Iwai   [ALSA] Remove xxx...
937
938
  	struct rme32 *rme32 = snd_pcm_substream_chip(substream);
  	struct snd_pcm_runtime *runtime = substream->runtime;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
939
940
941
942
943
944
945
946
947
  
  	if (rme32->fullduplex_mode)
  		runtime->hw = snd_rme32_adat_fd_info;
  	else
  		runtime->hw = snd_rme32_adat_info;
  	if ((rate = snd_rme32_capture_getrate(rme32, &isadat)) > 0) {
  		if (!isadat) {
  			return -EIO;
  		}
918f3a0e8   Clemens Ladisch   [ALSA] pcm: add s...
948
                  runtime->hw.rates = snd_pcm_rate_to_rate_bit(rate);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
                  runtime->hw.rate_min = rate;
                  runtime->hw.rate_max = rate;
          }
  
  	snd_pcm_set_sync(substream);
          
  	spin_lock_irq(&rme32->lock);	
  	if (rme32->capture_substream != NULL) {
  		spin_unlock_irq(&rme32->lock);
  		return -EBUSY;
          }
  	rme32->capture_substream = substream;
  	spin_unlock_irq(&rme32->lock);
  
  	snd_rme32_set_buffer_constraint(rme32, runtime);
  	return 0;
  }
017ce8023   Takashi Iwai   [ALSA] Remove xxx...
966
  static int snd_rme32_playback_close(struct snd_pcm_substream *substream)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
967
  {
017ce8023   Takashi Iwai   [ALSA] Remove xxx...
968
  	struct rme32 *rme32 = snd_pcm_substream_chip(substream);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
  	int spdif = 0;
  
  	spin_lock_irq(&rme32->lock);
  	rme32->playback_substream = NULL;
  	rme32->playback_periodsize = 0;
  	spdif = (rme32->wcreg & RME32_WCR_ADAT) == 0;
  	spin_unlock_irq(&rme32->lock);
  	if (spdif) {
  		rme32->spdif_ctl->vd[0].access |= SNDRV_CTL_ELEM_ACCESS_INACTIVE;
  		snd_ctl_notify(rme32->card, SNDRV_CTL_EVENT_MASK_VALUE |
  			       SNDRV_CTL_EVENT_MASK_INFO,
  			       &rme32->spdif_ctl->id);
  	}
  	return 0;
  }
017ce8023   Takashi Iwai   [ALSA] Remove xxx...
984
  static int snd_rme32_capture_close(struct snd_pcm_substream *substream)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
985
  {
017ce8023   Takashi Iwai   [ALSA] Remove xxx...
986
  	struct rme32 *rme32 = snd_pcm_substream_chip(substream);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
987
988
989
990
  
  	spin_lock_irq(&rme32->lock);
  	rme32->capture_substream = NULL;
  	rme32->capture_periodsize = 0;
f49a59c44   Denis Efremov   ALSA: rme32.c irq...
991
  	spin_unlock_irq(&rme32->lock);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
992
993
  	return 0;
  }
017ce8023   Takashi Iwai   [ALSA] Remove xxx...
994
  static int snd_rme32_playback_prepare(struct snd_pcm_substream *substream)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
995
  {
017ce8023   Takashi Iwai   [ALSA] Remove xxx...
996
  	struct rme32 *rme32 = snd_pcm_substream_chip(substream);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
997
998
999
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
  
  	spin_lock_irq(&rme32->lock);
  	if (rme32->fullduplex_mode) {
  		memset(&rme32->playback_pcm, 0, sizeof(rme32->playback_pcm));
  		rme32->playback_pcm.hw_buffer_size = RME32_BUFFER_SIZE;
  		rme32->playback_pcm.sw_buffer_size = snd_pcm_lib_buffer_bytes(substream);
  	} else {
  		writel(0, rme32->iobase + RME32_IO_RESET_POS);
  	}
  	if (rme32->wcreg & RME32_WCR_SEL)
  		rme32->wcreg &= ~RME32_WCR_MUTE;
  	writel(rme32->wcreg, rme32->iobase + RME32_IO_CONTROL_REGISTER);
  	spin_unlock_irq(&rme32->lock);
  	return 0;
  }
017ce8023   Takashi Iwai   [ALSA] Remove xxx...
1012
  static int snd_rme32_capture_prepare(struct snd_pcm_substream *substream)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1013
  {
017ce8023   Takashi Iwai   [ALSA] Remove xxx...
1014
  	struct rme32 *rme32 = snd_pcm_substream_chip(substream);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
  
  	spin_lock_irq(&rme32->lock);
  	if (rme32->fullduplex_mode) {
  		memset(&rme32->capture_pcm, 0, sizeof(rme32->capture_pcm));
  		rme32->capture_pcm.hw_buffer_size = RME32_BUFFER_SIZE;
  		rme32->capture_pcm.hw_queue_size = RME32_BUFFER_SIZE / 2;
  		rme32->capture_pcm.sw_buffer_size = snd_pcm_lib_buffer_bytes(substream);
  	} else {
  		writel(0, rme32->iobase + RME32_IO_RESET_POS);
  	}
  	spin_unlock_irq(&rme32->lock);
  	return 0;
  }
  
  static int
017ce8023   Takashi Iwai   [ALSA] Remove xxx...
1030
  snd_rme32_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1031
  {
017ce8023   Takashi Iwai   [ALSA] Remove xxx...
1032
  	struct rme32 *rme32 = snd_pcm_substream_chip(substream);
017ce8023   Takashi Iwai   [ALSA] Remove xxx...
1033
  	struct snd_pcm_substream *s;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1034
1035
  
  	spin_lock(&rme32->lock);
ef991b95a   Takashi Iwai   [ALSA] Add snd_pc...
1036
  	snd_pcm_group_for_each_entry(s, substream) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1037
1038
1039
1040
1041
1042
1043
1044
1045
1046
1047
1048
1049
1050
1051
1052
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062
  		if (s != rme32->playback_substream &&
  		    s != rme32->capture_substream)
  			continue;
  		switch (cmd) {
  		case SNDRV_PCM_TRIGGER_START:
  			rme32->running |= (1 << s->stream);
  			if (rme32->fullduplex_mode) {
  				/* remember the current DMA position */
  				if (s == rme32->playback_substream) {
  					rme32->playback_pcm.hw_io =
  					rme32->playback_pcm.hw_data = snd_rme32_pcm_byteptr(rme32);
  				} else {
  					rme32->capture_pcm.hw_io =
  					rme32->capture_pcm.hw_data = snd_rme32_pcm_byteptr(rme32);
  				}
  			}
  			break;
  		case SNDRV_PCM_TRIGGER_STOP:
  			rme32->running &= ~(1 << s->stream);
  			break;
  		}
  		snd_pcm_trigger_done(s, substream);
  	}
  	
  	/* prefill playback buffer */
  	if (cmd == SNDRV_PCM_TRIGGER_START && rme32->fullduplex_mode) {
ef991b95a   Takashi Iwai   [ALSA] Add snd_pc...
1063
  		snd_pcm_group_for_each_entry(s, substream) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1064
1065
1066
1067
1068
1069
1070
1071
1072
1073
1074
1075
1076
1077
1078
1079
1080
1081
1082
1083
1084
1085
1086
1087
1088
1089
1090
1091
1092
1093
1094
  			if (s == rme32->playback_substream) {
  				s->ops->ack(s);
  				break;
  			}
  		}
  	}
  
  	switch (cmd) {
  	case SNDRV_PCM_TRIGGER_START:
  		if (rme32->running && ! RME32_ISWORKING(rme32))
  			snd_rme32_pcm_start(rme32, 0);
  		break;
  	case SNDRV_PCM_TRIGGER_STOP:
  		if (! rme32->running && RME32_ISWORKING(rme32))
  			snd_rme32_pcm_stop(rme32, 0);
  		break;
  	case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
  		if (rme32->running && RME32_ISWORKING(rme32))
  			snd_rme32_pcm_stop(rme32, 1);
  		break;
  	case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
  		if (rme32->running && ! RME32_ISWORKING(rme32))
  			snd_rme32_pcm_start(rme32, 1);
  		break;
  	}
  	spin_unlock(&rme32->lock);
  	return 0;
  }
  
  /* pointer callback for halfduplex mode */
  static snd_pcm_uframes_t
017ce8023   Takashi Iwai   [ALSA] Remove xxx...
1095
  snd_rme32_playback_pointer(struct snd_pcm_substream *substream)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1096
  {
017ce8023   Takashi Iwai   [ALSA] Remove xxx...
1097
  	struct rme32 *rme32 = snd_pcm_substream_chip(substream);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1098
1099
1100
1101
  	return snd_rme32_pcm_byteptr(rme32) >> rme32->playback_frlog;
  }
  
  static snd_pcm_uframes_t
017ce8023   Takashi Iwai   [ALSA] Remove xxx...
1102
  snd_rme32_capture_pointer(struct snd_pcm_substream *substream)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1103
  {
017ce8023   Takashi Iwai   [ALSA] Remove xxx...
1104
  	struct rme32 *rme32 = snd_pcm_substream_chip(substream);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1105
1106
1107
1108
1109
  	return snd_rme32_pcm_byteptr(rme32) >> rme32->capture_frlog;
  }
  
  
  /* ack and pointer callbacks for fullduplex mode */
017ce8023   Takashi Iwai   [ALSA] Remove xxx...
1110
1111
  static void snd_rme32_pb_trans_copy(struct snd_pcm_substream *substream,
  				    struct snd_pcm_indirect *rec, size_t bytes)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1112
  {
017ce8023   Takashi Iwai   [ALSA] Remove xxx...
1113
  	struct rme32 *rme32 = snd_pcm_substream_chip(substream);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1114
1115
1116
  	memcpy_toio(rme32->iobase + RME32_IO_DATA_BUFFER + rec->hw_data,
  		    substream->runtime->dma_area + rec->sw_data, bytes);
  }
017ce8023   Takashi Iwai   [ALSA] Remove xxx...
1117
  static int snd_rme32_playback_fd_ack(struct snd_pcm_substream *substream)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1118
  {
017ce8023   Takashi Iwai   [ALSA] Remove xxx...
1119
1120
  	struct rme32 *rme32 = snd_pcm_substream_chip(substream);
  	struct snd_pcm_indirect *rec, *cprec;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1121
1122
1123
1124
1125
1126
1127
1128
1129
1130
1131
1132
  
  	rec = &rme32->playback_pcm;
  	cprec = &rme32->capture_pcm;
  	spin_lock(&rme32->lock);
  	rec->hw_queue_size = RME32_BUFFER_SIZE;
  	if (rme32->running & (1 << SNDRV_PCM_STREAM_CAPTURE))
  		rec->hw_queue_size -= cprec->hw_ready;
  	spin_unlock(&rme32->lock);
  	snd_pcm_indirect_playback_transfer(substream, rec,
  					   snd_rme32_pb_trans_copy);
  	return 0;
  }
017ce8023   Takashi Iwai   [ALSA] Remove xxx...
1133
1134
  static void snd_rme32_cp_trans_copy(struct snd_pcm_substream *substream,
  				    struct snd_pcm_indirect *rec, size_t bytes)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1135
  {
017ce8023   Takashi Iwai   [ALSA] Remove xxx...
1136
  	struct rme32 *rme32 = snd_pcm_substream_chip(substream);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1137
1138
1139
1140
  	memcpy_fromio(substream->runtime->dma_area + rec->sw_data,
  		      rme32->iobase + RME32_IO_DATA_BUFFER + rec->hw_data,
  		      bytes);
  }
017ce8023   Takashi Iwai   [ALSA] Remove xxx...
1141
  static int snd_rme32_capture_fd_ack(struct snd_pcm_substream *substream)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1142
  {
017ce8023   Takashi Iwai   [ALSA] Remove xxx...
1143
  	struct rme32 *rme32 = snd_pcm_substream_chip(substream);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1144
1145
1146
1147
1148
1149
  	snd_pcm_indirect_capture_transfer(substream, &rme32->capture_pcm,
  					  snd_rme32_cp_trans_copy);
  	return 0;
  }
  
  static snd_pcm_uframes_t
017ce8023   Takashi Iwai   [ALSA] Remove xxx...
1150
  snd_rme32_playback_fd_pointer(struct snd_pcm_substream *substream)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1151
  {
017ce8023   Takashi Iwai   [ALSA] Remove xxx...
1152
  	struct rme32 *rme32 = snd_pcm_substream_chip(substream);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1153
1154
1155
1156
1157
  	return snd_pcm_indirect_playback_pointer(substream, &rme32->playback_pcm,
  						 snd_rme32_pcm_byteptr(rme32));
  }
  
  static snd_pcm_uframes_t
017ce8023   Takashi Iwai   [ALSA] Remove xxx...
1158
  snd_rme32_capture_fd_pointer(struct snd_pcm_substream *substream)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1159
  {
017ce8023   Takashi Iwai   [ALSA] Remove xxx...
1160
  	struct rme32 *rme32 = snd_pcm_substream_chip(substream);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1161
1162
1163
1164
1165
  	return snd_pcm_indirect_capture_pointer(substream, &rme32->capture_pcm,
  						snd_rme32_pcm_byteptr(rme32));
  }
  
  /* for halfduplex mode */
017ce8023   Takashi Iwai   [ALSA] Remove xxx...
1166
  static struct snd_pcm_ops snd_rme32_playback_spdif_ops = {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1167
1168
1169
1170
1171
1172
1173
1174
1175
1176
1177
1178
  	.open =		snd_rme32_playback_spdif_open,
  	.close =	snd_rme32_playback_close,
  	.ioctl =	snd_pcm_lib_ioctl,
  	.hw_params =	snd_rme32_playback_hw_params,
  	.hw_free =	snd_rme32_pcm_hw_free,
  	.prepare =	snd_rme32_playback_prepare,
  	.trigger =	snd_rme32_pcm_trigger,
  	.pointer =	snd_rme32_playback_pointer,
  	.copy =		snd_rme32_playback_copy,
  	.silence =	snd_rme32_playback_silence,
  	.mmap =		snd_pcm_lib_mmap_iomem,
  };
017ce8023   Takashi Iwai   [ALSA] Remove xxx...
1179
  static struct snd_pcm_ops snd_rme32_capture_spdif_ops = {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1180
1181
1182
1183
1184
1185
1186
1187
1188
1189
1190
  	.open =		snd_rme32_capture_spdif_open,
  	.close =	snd_rme32_capture_close,
  	.ioctl =	snd_pcm_lib_ioctl,
  	.hw_params =	snd_rme32_capture_hw_params,
  	.hw_free =	snd_rme32_pcm_hw_free,
  	.prepare =	snd_rme32_capture_prepare,
  	.trigger =	snd_rme32_pcm_trigger,
  	.pointer =	snd_rme32_capture_pointer,
  	.copy =		snd_rme32_capture_copy,
  	.mmap =		snd_pcm_lib_mmap_iomem,
  };
017ce8023   Takashi Iwai   [ALSA] Remove xxx...
1191
  static struct snd_pcm_ops snd_rme32_playback_adat_ops = {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1192
1193
1194
1195
1196
1197
1198
1199
1200
1201
1202
  	.open =		snd_rme32_playback_adat_open,
  	.close =	snd_rme32_playback_close,
  	.ioctl =	snd_pcm_lib_ioctl,
  	.hw_params =	snd_rme32_playback_hw_params,
  	.prepare =	snd_rme32_playback_prepare,
  	.trigger =	snd_rme32_pcm_trigger,
  	.pointer =	snd_rme32_playback_pointer,
  	.copy =		snd_rme32_playback_copy,
  	.silence =	snd_rme32_playback_silence,
  	.mmap =		snd_pcm_lib_mmap_iomem,
  };
017ce8023   Takashi Iwai   [ALSA] Remove xxx...
1203
  static struct snd_pcm_ops snd_rme32_capture_adat_ops = {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1204
1205
1206
1207
1208
1209
1210
1211
1212
1213
1214
1215
  	.open =		snd_rme32_capture_adat_open,
  	.close =	snd_rme32_capture_close,
  	.ioctl =	snd_pcm_lib_ioctl,
  	.hw_params =	snd_rme32_capture_hw_params,
  	.prepare =	snd_rme32_capture_prepare,
  	.trigger =	snd_rme32_pcm_trigger,
  	.pointer =	snd_rme32_capture_pointer,
  	.copy =		snd_rme32_capture_copy,
  	.mmap =		snd_pcm_lib_mmap_iomem,
  };
  
  /* for fullduplex mode */
017ce8023   Takashi Iwai   [ALSA] Remove xxx...
1216
  static struct snd_pcm_ops snd_rme32_playback_spdif_fd_ops = {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1217
1218
1219
1220
1221
1222
1223
1224
1225
1226
  	.open =		snd_rme32_playback_spdif_open,
  	.close =	snd_rme32_playback_close,
  	.ioctl =	snd_pcm_lib_ioctl,
  	.hw_params =	snd_rme32_playback_hw_params,
  	.hw_free =	snd_rme32_pcm_hw_free,
  	.prepare =	snd_rme32_playback_prepare,
  	.trigger =	snd_rme32_pcm_trigger,
  	.pointer =	snd_rme32_playback_fd_pointer,
  	.ack =		snd_rme32_playback_fd_ack,
  };
017ce8023   Takashi Iwai   [ALSA] Remove xxx...
1227
  static struct snd_pcm_ops snd_rme32_capture_spdif_fd_ops = {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1228
1229
1230
1231
1232
1233
1234
1235
1236
1237
  	.open =		snd_rme32_capture_spdif_open,
  	.close =	snd_rme32_capture_close,
  	.ioctl =	snd_pcm_lib_ioctl,
  	.hw_params =	snd_rme32_capture_hw_params,
  	.hw_free =	snd_rme32_pcm_hw_free,
  	.prepare =	snd_rme32_capture_prepare,
  	.trigger =	snd_rme32_pcm_trigger,
  	.pointer =	snd_rme32_capture_fd_pointer,
  	.ack =		snd_rme32_capture_fd_ack,
  };
017ce8023   Takashi Iwai   [ALSA] Remove xxx...
1238
  static struct snd_pcm_ops snd_rme32_playback_adat_fd_ops = {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1239
1240
1241
1242
1243
1244
1245
1246
1247
  	.open =		snd_rme32_playback_adat_open,
  	.close =	snd_rme32_playback_close,
  	.ioctl =	snd_pcm_lib_ioctl,
  	.hw_params =	snd_rme32_playback_hw_params,
  	.prepare =	snd_rme32_playback_prepare,
  	.trigger =	snd_rme32_pcm_trigger,
  	.pointer =	snd_rme32_playback_fd_pointer,
  	.ack =		snd_rme32_playback_fd_ack,
  };
017ce8023   Takashi Iwai   [ALSA] Remove xxx...
1248
  static struct snd_pcm_ops snd_rme32_capture_adat_fd_ops = {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1249
1250
1251
1252
1253
1254
1255
1256
1257
1258
1259
1260
  	.open =		snd_rme32_capture_adat_open,
  	.close =	snd_rme32_capture_close,
  	.ioctl =	snd_pcm_lib_ioctl,
  	.hw_params =	snd_rme32_capture_hw_params,
  	.prepare =	snd_rme32_capture_prepare,
  	.trigger =	snd_rme32_pcm_trigger,
  	.pointer =	snd_rme32_capture_fd_pointer,
  	.ack =		snd_rme32_capture_fd_ack,
  };
  
  static void snd_rme32_free(void *private_data)
  {
017ce8023   Takashi Iwai   [ALSA] Remove xxx...
1261
  	struct rme32 *rme32 = (struct rme32 *) private_data;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1262
1263
1264
1265
1266
1267
1268
1269
1270
1271
1272
1273
1274
1275
1276
1277
1278
1279
1280
  
  	if (rme32 == NULL) {
  		return;
  	}
  	if (rme32->irq >= 0) {
  		snd_rme32_pcm_stop(rme32, 0);
  		free_irq(rme32->irq, (void *) rme32);
  		rme32->irq = -1;
  	}
  	if (rme32->iobase) {
  		iounmap(rme32->iobase);
  		rme32->iobase = NULL;
  	}
  	if (rme32->port) {
  		pci_release_regions(rme32->pci);
  		rme32->port = 0;
  	}
  	pci_disable_device(rme32->pci);
  }
017ce8023   Takashi Iwai   [ALSA] Remove xxx...
1281
  static void snd_rme32_free_spdif_pcm(struct snd_pcm *pcm)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1282
  {
017ce8023   Takashi Iwai   [ALSA] Remove xxx...
1283
  	struct rme32 *rme32 = (struct rme32 *) pcm->private_data;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1284
1285
1286
1287
  	rme32->spdif_pcm = NULL;
  }
  
  static void
017ce8023   Takashi Iwai   [ALSA] Remove xxx...
1288
  snd_rme32_free_adat_pcm(struct snd_pcm *pcm)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1289
  {
017ce8023   Takashi Iwai   [ALSA] Remove xxx...
1290
  	struct rme32 *rme32 = (struct rme32 *) pcm->private_data;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1291
1292
  	rme32->adat_pcm = NULL;
  }
e23e7a143   Bill Pemberton   ALSA: pci: remove...
1293
  static int snd_rme32_create(struct rme32 *rme32)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1294
1295
1296
1297
1298
1299
1300
1301
1302
1303
1304
1305
1306
  {
  	struct pci_dev *pci = rme32->pci;
  	int err;
  
  	rme32->irq = -1;
  	spin_lock_init(&rme32->lock);
  
  	if ((err = pci_enable_device(pci)) < 0)
  		return err;
  
  	if ((err = pci_request_regions(pci, "RME32")) < 0)
  		return err;
  	rme32->port = pci_resource_start(rme32->pci, 0);
4db9e4f2b   Harvey Harrison   [ALSA] sound: rme...
1307
1308
  	rme32->iobase = ioremap_nocache(rme32->port, RME32_IO_SIZE);
  	if (!rme32->iobase) {
03952a3e2   Takashi Iwai   ALSA: rme32: Use ...
1309
1310
1311
  		dev_err(rme32->card->dev,
  			"unable to remap memory region 0x%lx-0x%lx
  ",
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1312
1313
1314
  			   rme32->port, rme32->port + RME32_IO_SIZE - 1);
  		return -ENOMEM;
  	}
437a5a460   Takashi Iwai   [ALSA] Remove IRQ...
1315
  	if (request_irq(pci->irq, snd_rme32_interrupt, IRQF_SHARED,
934c2b6d0   Takashi Iwai   ALSA: use KBUILD_...
1316
  			KBUILD_MODNAME, rme32)) {
03952a3e2   Takashi Iwai   ALSA: rme32: Use ...
1317
1318
  		dev_err(rme32->card->dev, "unable to grab IRQ %d
  ", pci->irq);
688956f23   Takashi Iwai   [ALSA] Fix races ...
1319
1320
1321
  		return -EBUSY;
  	}
  	rme32->irq = pci->irq;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1322
1323
1324
1325
1326
1327
1328
1329
1330
1331
1332
1333
1334
1335
1336
1337
1338
1339
1340
1341
1342
1343
1344
1345
1346
1347
1348
1349
  	/* read the card's revision number */
  	pci_read_config_byte(pci, 8, &rme32->rev);
  
  	/* set up ALSA pcm device for S/PDIF */
  	if ((err = snd_pcm_new(rme32->card, "Digi32 IEC958", 0, 1, 1, &rme32->spdif_pcm)) < 0) {
  		return err;
  	}
  	rme32->spdif_pcm->private_data = rme32;
  	rme32->spdif_pcm->private_free = snd_rme32_free_spdif_pcm;
  	strcpy(rme32->spdif_pcm->name, "Digi32 IEC958");
  	if (rme32->fullduplex_mode) {
  		snd_pcm_set_ops(rme32->spdif_pcm, SNDRV_PCM_STREAM_PLAYBACK,
  				&snd_rme32_playback_spdif_fd_ops);
  		snd_pcm_set_ops(rme32->spdif_pcm, SNDRV_PCM_STREAM_CAPTURE,
  				&snd_rme32_capture_spdif_fd_ops);
  		snd_pcm_lib_preallocate_pages_for_all(rme32->spdif_pcm, SNDRV_DMA_TYPE_CONTINUOUS,
  						      snd_dma_continuous_data(GFP_KERNEL),
  						      0, RME32_MID_BUFFER_SIZE);
  		rme32->spdif_pcm->info_flags = SNDRV_PCM_INFO_JOINT_DUPLEX;
  	} else {
  		snd_pcm_set_ops(rme32->spdif_pcm, SNDRV_PCM_STREAM_PLAYBACK,
  				&snd_rme32_playback_spdif_ops);
  		snd_pcm_set_ops(rme32->spdif_pcm, SNDRV_PCM_STREAM_CAPTURE,
  				&snd_rme32_capture_spdif_ops);
  		rme32->spdif_pcm->info_flags = SNDRV_PCM_INFO_HALF_DUPLEX;
  	}
  
  	/* set up ALSA pcm device for ADAT */
8b7fc4214   Roland Dreier   [PATCH] add PCI I...
1350
1351
  	if ((pci->device == PCI_DEVICE_ID_RME_DIGI32) ||
  	    (pci->device == PCI_DEVICE_ID_RME_DIGI32_PRO)) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1352
1353
1354
1355
1356
1357
1358
1359
1360
1361
1362
1363
1364
1365
1366
1367
1368
1369
1370
1371
1372
1373
1374
1375
1376
1377
1378
1379
1380
1381
1382
1383
1384
1385
1386
1387
1388
1389
1390
1391
1392
1393
1394
1395
1396
1397
1398
1399
1400
1401
1402
1403
1404
1405
1406
1407
1408
1409
1410
1411
1412
1413
1414
1415
1416
1417
1418
1419
1420
  		/* ADAT is not available on DIGI32 and DIGI32 Pro */
  		rme32->adat_pcm = NULL;
  	}
  	else {
  		if ((err = snd_pcm_new(rme32->card, "Digi32 ADAT", 1,
  				       1, 1, &rme32->adat_pcm)) < 0)
  		{
  			return err;
  		}		
  		rme32->adat_pcm->private_data = rme32;
  		rme32->adat_pcm->private_free = snd_rme32_free_adat_pcm;
  		strcpy(rme32->adat_pcm->name, "Digi32 ADAT");
  		if (rme32->fullduplex_mode) {
  			snd_pcm_set_ops(rme32->adat_pcm, SNDRV_PCM_STREAM_PLAYBACK, 
  					&snd_rme32_playback_adat_fd_ops);
  			snd_pcm_set_ops(rme32->adat_pcm, SNDRV_PCM_STREAM_CAPTURE, 
  					&snd_rme32_capture_adat_fd_ops);
  			snd_pcm_lib_preallocate_pages_for_all(rme32->adat_pcm, SNDRV_DMA_TYPE_CONTINUOUS,
  							      snd_dma_continuous_data(GFP_KERNEL),
  							      0, RME32_MID_BUFFER_SIZE);
  			rme32->adat_pcm->info_flags = SNDRV_PCM_INFO_JOINT_DUPLEX;
  		} else {
  			snd_pcm_set_ops(rme32->adat_pcm, SNDRV_PCM_STREAM_PLAYBACK, 
  					&snd_rme32_playback_adat_ops);
  			snd_pcm_set_ops(rme32->adat_pcm, SNDRV_PCM_STREAM_CAPTURE, 
  					&snd_rme32_capture_adat_ops);
  			rme32->adat_pcm->info_flags = SNDRV_PCM_INFO_HALF_DUPLEX;
  		}
  	}
  
  
  	rme32->playback_periodsize = 0;
  	rme32->capture_periodsize = 0;
  
  	/* make sure playback/capture is stopped, if by some reason active */
  	snd_rme32_pcm_stop(rme32, 0);
  
          /* reset DAC */
          snd_rme32_reset_dac(rme32);
  
  	/* reset buffer pointer */
  	writel(0, rme32->iobase + RME32_IO_RESET_POS);
  
  	/* set default values in registers */
  	rme32->wcreg = RME32_WCR_SEL |	 /* normal playback */
  		RME32_WCR_INP_0 | /* input select */
  		RME32_WCR_MUTE;	 /* muting on */
  	writel(rme32->wcreg, rme32->iobase + RME32_IO_CONTROL_REGISTER);
  
  
  	/* init switch interface */
  	if ((err = snd_rme32_create_switches(rme32->card, rme32)) < 0) {
  		return err;
  	}
  
  	/* init proc interface */
  	snd_rme32_proc_init(rme32);
  
  	rme32->capture_substream = NULL;
  	rme32->playback_substream = NULL;
  
  	return 0;
  }
  
  /*
   * proc interface
   */
  
  static void
017ce8023   Takashi Iwai   [ALSA] Remove xxx...
1421
  snd_rme32_proc_read(struct snd_info_entry * entry, struct snd_info_buffer *buffer)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1422
1423
  {
  	int n;
017ce8023   Takashi Iwai   [ALSA] Remove xxx...
1424
  	struct rme32 *rme32 = (struct rme32 *) entry->private_data;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1425
1426
1427
1428
1429
1430
1431
1432
1433
1434
1435
1436
1437
1438
1439
1440
1441
1442
1443
1444
1445
1446
1447
1448
1449
1450
1451
1452
1453
1454
1455
1456
1457
1458
1459
1460
1461
1462
1463
1464
1465
1466
1467
1468
1469
1470
1471
1472
1473
1474
1475
1476
1477
1478
1479
1480
1481
1482
1483
1484
1485
1486
1487
1488
1489
1490
1491
1492
1493
1494
1495
1496
1497
1498
1499
1500
1501
1502
1503
1504
1505
1506
1507
1508
1509
1510
1511
1512
1513
1514
1515
1516
1517
1518
1519
1520
1521
1522
1523
1524
1525
1526
1527
1528
1529
1530
1531
1532
1533
1534
1535
1536
1537
1538
1539
1540
  
  	rme32->rcreg = readl(rme32->iobase + RME32_IO_CONTROL_REGISTER);
  
  	snd_iprintf(buffer, rme32->card->longname);
  	snd_iprintf(buffer, " (index #%d)
  ", rme32->card->number + 1);
  
  	snd_iprintf(buffer, "
  General settings
  ");
  	if (rme32->fullduplex_mode)
  		snd_iprintf(buffer, "  Full-duplex mode
  ");
  	else
  		snd_iprintf(buffer, "  Half-duplex mode
  ");
  	if (RME32_PRO_WITH_8414(rme32)) {
  		snd_iprintf(buffer, "  receiver: CS8414
  ");
  	} else {
  		snd_iprintf(buffer, "  receiver: CS8412
  ");
  	}
  	if (rme32->wcreg & RME32_WCR_MODE24) {
  		snd_iprintf(buffer, "  format: 24 bit");
  	} else {
  		snd_iprintf(buffer, "  format: 16 bit");
  	}
  	if (rme32->wcreg & RME32_WCR_MONO) {
  		snd_iprintf(buffer, ", Mono
  ");
  	} else {
  		snd_iprintf(buffer, ", Stereo
  ");
  	}
  
  	snd_iprintf(buffer, "
  Input settings
  ");
  	switch (snd_rme32_getinputtype(rme32)) {
  	case RME32_INPUT_OPTICAL:
  		snd_iprintf(buffer, "  input: optical");
  		break;
  	case RME32_INPUT_COAXIAL:
  		snd_iprintf(buffer, "  input: coaxial");
  		break;
  	case RME32_INPUT_INTERNAL:
  		snd_iprintf(buffer, "  input: internal");
  		break;
  	case RME32_INPUT_XLR:
  		snd_iprintf(buffer, "  input: XLR");
  		break;
  	}
  	if (snd_rme32_capture_getrate(rme32, &n) < 0) {
  		snd_iprintf(buffer, "
    sample rate: no valid signal
  ");
  	} else {
  		if (n) {
  			snd_iprintf(buffer, " (8 channels)
  ");
  		} else {
  			snd_iprintf(buffer, " (2 channels)
  ");
  		}
  		snd_iprintf(buffer, "  sample rate: %d Hz
  ",
  			    snd_rme32_capture_getrate(rme32, &n));
  	}
  
  	snd_iprintf(buffer, "
  Output settings
  ");
  	if (rme32->wcreg & RME32_WCR_SEL) {
  		snd_iprintf(buffer, "  output signal: normal playback");
  	} else {
  		snd_iprintf(buffer, "  output signal: same as input");
  	}
  	if (rme32->wcreg & RME32_WCR_MUTE) {
  		snd_iprintf(buffer, " (muted)
  ");
  	} else {
  		snd_iprintf(buffer, "
  ");
  	}
  
  	/* master output frequency */
  	if (!
  	    ((!(rme32->wcreg & RME32_WCR_FREQ_0))
  	     && (!(rme32->wcreg & RME32_WCR_FREQ_1)))) {
  		snd_iprintf(buffer, "  sample rate: %d Hz
  ",
  			    snd_rme32_playback_getrate(rme32));
  	}
  	if (rme32->rcreg & RME32_RCR_KMODE) {
  		snd_iprintf(buffer, "  sample clock source: AutoSync
  ");
  	} else {
  		snd_iprintf(buffer, "  sample clock source: Internal
  ");
  	}
  	if (rme32->wcreg & RME32_WCR_PRO) {
  		snd_iprintf(buffer, "  format: AES/EBU (professional)
  ");
  	} else {
  		snd_iprintf(buffer, "  format: IEC958 (consumer)
  ");
  	}
  	if (rme32->wcreg & RME32_WCR_EMP) {
  		snd_iprintf(buffer, "  emphasis: on
  ");
  	} else {
  		snd_iprintf(buffer, "  emphasis: off
  ");
  	}
  }
e23e7a143   Bill Pemberton   ALSA: pci: remove...
1541
  static void snd_rme32_proc_init(struct rme32 *rme32)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1542
  {
017ce8023   Takashi Iwai   [ALSA] Remove xxx...
1543
  	struct snd_info_entry *entry;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1544
1545
  
  	if (! snd_card_proc_new(rme32->card, "rme32", &entry))
bf850204a   Takashi Iwai   [ALSA] Remove unn...
1546
  		snd_info_set_text_ops(entry, rme32, snd_rme32_proc_read);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1547
1548
1549
1550
1551
  }
  
  /*
   * control interface
   */
a5ce88909   Takashi Iwai   [ALSA] Clean up w...
1552
  #define snd_rme32_info_loopback_control		snd_ctl_boolean_mono_info
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1553
  static int
017ce8023   Takashi Iwai   [ALSA] Remove xxx...
1554
1555
  snd_rme32_get_loopback_control(struct snd_kcontrol *kcontrol,
  			       struct snd_ctl_elem_value *ucontrol)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1556
  {
017ce8023   Takashi Iwai   [ALSA] Remove xxx...
1557
  	struct rme32 *rme32 = snd_kcontrol_chip(kcontrol);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1558
1559
1560
1561
1562
1563
1564
1565
  
  	spin_lock_irq(&rme32->lock);
  	ucontrol->value.integer.value[0] =
  	    rme32->wcreg & RME32_WCR_SEL ? 0 : 1;
  	spin_unlock_irq(&rme32->lock);
  	return 0;
  }
  static int
017ce8023   Takashi Iwai   [ALSA] Remove xxx...
1566
1567
  snd_rme32_put_loopback_control(struct snd_kcontrol *kcontrol,
  			       struct snd_ctl_elem_value *ucontrol)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1568
  {
017ce8023   Takashi Iwai   [ALSA] Remove xxx...
1569
  	struct rme32 *rme32 = snd_kcontrol_chip(kcontrol);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1570
1571
1572
1573
1574
1575
1576
1577
1578
1579
1580
1581
1582
1583
1584
1585
1586
1587
  	unsigned int val;
  	int change;
  
  	val = ucontrol->value.integer.value[0] ? 0 : RME32_WCR_SEL;
  	spin_lock_irq(&rme32->lock);
  	val = (rme32->wcreg & ~RME32_WCR_SEL) | val;
  	change = val != rme32->wcreg;
  	if (ucontrol->value.integer.value[0])
  		val &= ~RME32_WCR_MUTE;
  	else
  		val |= RME32_WCR_MUTE;
  	rme32->wcreg = val;
  	writel(val, rme32->iobase + RME32_IO_CONTROL_REGISTER);
  	spin_unlock_irq(&rme32->lock);
  	return change;
  }
  
  static int
017ce8023   Takashi Iwai   [ALSA] Remove xxx...
1588
1589
  snd_rme32_info_inputtype_control(struct snd_kcontrol *kcontrol,
  				 struct snd_ctl_elem_info *uinfo)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1590
  {
017ce8023   Takashi Iwai   [ALSA] Remove xxx...
1591
  	struct rme32 *rme32 = snd_kcontrol_chip(kcontrol);
11c6ef7c8   Takashi Iwai   ALSA: rme32: Use ...
1592
1593
1594
1595
  	static const char * const texts[4] = {
  		"Optical", "Coaxial", "Internal", "XLR"
  	};
  	int num_items;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1596

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1597
  	switch (rme32->pci->device) {
8b7fc4214   Roland Dreier   [PATCH] add PCI I...
1598
1599
  	case PCI_DEVICE_ID_RME_DIGI32:
  	case PCI_DEVICE_ID_RME_DIGI32_8:
11c6ef7c8   Takashi Iwai   ALSA: rme32: Use ...
1600
  		num_items = 3;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1601
  		break;
8b7fc4214   Roland Dreier   [PATCH] add PCI I...
1602
  	case PCI_DEVICE_ID_RME_DIGI32_PRO:
11c6ef7c8   Takashi Iwai   ALSA: rme32: Use ...
1603
  		num_items = 4;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1604
1605
1606
  		break;
  	default:
  		snd_BUG();
11c6ef7c8   Takashi Iwai   ALSA: rme32: Use ...
1607
  		return -EINVAL;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1608
  	}
11c6ef7c8   Takashi Iwai   ALSA: rme32: Use ...
1609
  	return snd_ctl_enum_info(uinfo, 1, num_items, texts);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1610
1611
  }
  static int
017ce8023   Takashi Iwai   [ALSA] Remove xxx...
1612
1613
  snd_rme32_get_inputtype_control(struct snd_kcontrol *kcontrol,
  				struct snd_ctl_elem_value *ucontrol)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1614
  {
017ce8023   Takashi Iwai   [ALSA] Remove xxx...
1615
  	struct rme32 *rme32 = snd_kcontrol_chip(kcontrol);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1616
1617
1618
1619
1620
1621
  	unsigned int items = 3;
  
  	spin_lock_irq(&rme32->lock);
  	ucontrol->value.enumerated.item[0] = snd_rme32_getinputtype(rme32);
  
  	switch (rme32->pci->device) {
8b7fc4214   Roland Dreier   [PATCH] add PCI I...
1622
1623
  	case PCI_DEVICE_ID_RME_DIGI32:
  	case PCI_DEVICE_ID_RME_DIGI32_8:
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1624
1625
  		items = 3;
  		break;
8b7fc4214   Roland Dreier   [PATCH] add PCI I...
1626
  	case PCI_DEVICE_ID_RME_DIGI32_PRO:
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1627
1628
1629
1630
1631
1632
1633
1634
1635
1636
1637
1638
1639
1640
  		items = 4;
  		break;
  	default:
  		snd_BUG();
  		break;
  	}
  	if (ucontrol->value.enumerated.item[0] >= items) {
  		ucontrol->value.enumerated.item[0] = items - 1;
  	}
  
  	spin_unlock_irq(&rme32->lock);
  	return 0;
  }
  static int
017ce8023   Takashi Iwai   [ALSA] Remove xxx...
1641
1642
  snd_rme32_put_inputtype_control(struct snd_kcontrol *kcontrol,
  				struct snd_ctl_elem_value *ucontrol)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1643
  {
017ce8023   Takashi Iwai   [ALSA] Remove xxx...
1644
  	struct rme32 *rme32 = snd_kcontrol_chip(kcontrol);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1645
1646
1647
1648
  	unsigned int val;
  	int change, items = 3;
  
  	switch (rme32->pci->device) {
8b7fc4214   Roland Dreier   [PATCH] add PCI I...
1649
1650
  	case PCI_DEVICE_ID_RME_DIGI32:
  	case PCI_DEVICE_ID_RME_DIGI32_8:
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1651
1652
  		items = 3;
  		break;
8b7fc4214   Roland Dreier   [PATCH] add PCI I...
1653
  	case PCI_DEVICE_ID_RME_DIGI32_PRO:
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1654
1655
1656
1657
1658
1659
1660
1661
1662
1663
1664
1665
1666
1667
1668
1669
  		items = 4;
  		break;
  	default:
  		snd_BUG();
  		break;
  	}
  	val = ucontrol->value.enumerated.item[0] % items;
  
  	spin_lock_irq(&rme32->lock);
  	change = val != (unsigned int)snd_rme32_getinputtype(rme32);
  	snd_rme32_setinputtype(rme32, val);
  	spin_unlock_irq(&rme32->lock);
  	return change;
  }
  
  static int
017ce8023   Takashi Iwai   [ALSA] Remove xxx...
1670
1671
  snd_rme32_info_clockmode_control(struct snd_kcontrol *kcontrol,
  				 struct snd_ctl_elem_info *uinfo)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1672
  {
11c6ef7c8   Takashi Iwai   ALSA: rme32: Use ...
1673
  	static const char * const texts[4] = { "AutoSync",
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1674
1675
1676
  				  "Internal 32.0kHz", 
  				  "Internal 44.1kHz", 
  				  "Internal 48.0kHz" };
11c6ef7c8   Takashi Iwai   ALSA: rme32: Use ...
1677
  	return snd_ctl_enum_info(uinfo, 1, 4, texts);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1678
1679
  }
  static int
017ce8023   Takashi Iwai   [ALSA] Remove xxx...
1680
1681
  snd_rme32_get_clockmode_control(struct snd_kcontrol *kcontrol,
  				struct snd_ctl_elem_value *ucontrol)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1682
  {
017ce8023   Takashi Iwai   [ALSA] Remove xxx...
1683
  	struct rme32 *rme32 = snd_kcontrol_chip(kcontrol);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1684
1685
1686
1687
1688
1689
1690
  
  	spin_lock_irq(&rme32->lock);
  	ucontrol->value.enumerated.item[0] = snd_rme32_getclockmode(rme32);
  	spin_unlock_irq(&rme32->lock);
  	return 0;
  }
  static int
017ce8023   Takashi Iwai   [ALSA] Remove xxx...
1691
1692
  snd_rme32_put_clockmode_control(struct snd_kcontrol *kcontrol,
  				struct snd_ctl_elem_value *ucontrol)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1693
  {
017ce8023   Takashi Iwai   [ALSA] Remove xxx...
1694
  	struct rme32 *rme32 = snd_kcontrol_chip(kcontrol);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1695
1696
1697
1698
1699
1700
1701
1702
1703
1704
  	unsigned int val;
  	int change;
  
  	val = ucontrol->value.enumerated.item[0] % 3;
  	spin_lock_irq(&rme32->lock);
  	change = val != (unsigned int)snd_rme32_getclockmode(rme32);
  	snd_rme32_setclockmode(rme32, val);
  	spin_unlock_irq(&rme32->lock);
  	return change;
  }
017ce8023   Takashi Iwai   [ALSA] Remove xxx...
1705
  static u32 snd_rme32_convert_from_aes(struct snd_aes_iec958 * aes)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1706
1707
1708
1709
1710
1711
1712
1713
1714
  {
  	u32 val = 0;
  	val |= (aes->status[0] & IEC958_AES0_PROFESSIONAL) ? RME32_WCR_PRO : 0;
  	if (val & RME32_WCR_PRO)
  		val |= (aes->status[0] & IEC958_AES0_PRO_EMPHASIS_5015) ? RME32_WCR_EMP : 0;
  	else
  		val |= (aes->status[0] & IEC958_AES0_CON_EMPHASIS_5015) ? RME32_WCR_EMP : 0;
  	return val;
  }
017ce8023   Takashi Iwai   [ALSA] Remove xxx...
1715
  static void snd_rme32_convert_to_aes(struct snd_aes_iec958 * aes, u32 val)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1716
1717
1718
1719
1720
1721
1722
  {
  	aes->status[0] = ((val & RME32_WCR_PRO) ? IEC958_AES0_PROFESSIONAL : 0);
  	if (val & RME32_WCR_PRO)
  		aes->status[0] |= (val & RME32_WCR_EMP) ? IEC958_AES0_PRO_EMPHASIS_5015 : 0;
  	else
  		aes->status[0] |= (val & RME32_WCR_EMP) ? IEC958_AES0_CON_EMPHASIS_5015 : 0;
  }
017ce8023   Takashi Iwai   [ALSA] Remove xxx...
1723
1724
  static int snd_rme32_control_spdif_info(struct snd_kcontrol *kcontrol,
  					struct snd_ctl_elem_info *uinfo)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1725
1726
1727
1728
1729
  {
  	uinfo->type = SNDRV_CTL_ELEM_TYPE_IEC958;
  	uinfo->count = 1;
  	return 0;
  }
017ce8023   Takashi Iwai   [ALSA] Remove xxx...
1730
1731
  static int snd_rme32_control_spdif_get(struct snd_kcontrol *kcontrol,
  				       struct snd_ctl_elem_value *ucontrol)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1732
  {
017ce8023   Takashi Iwai   [ALSA] Remove xxx...
1733
  	struct rme32 *rme32 = snd_kcontrol_chip(kcontrol);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1734
1735
1736
1737
1738
  
  	snd_rme32_convert_to_aes(&ucontrol->value.iec958,
  				 rme32->wcreg_spdif);
  	return 0;
  }
017ce8023   Takashi Iwai   [ALSA] Remove xxx...
1739
1740
  static int snd_rme32_control_spdif_put(struct snd_kcontrol *kcontrol,
  				       struct snd_ctl_elem_value *ucontrol)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1741
  {
017ce8023   Takashi Iwai   [ALSA] Remove xxx...
1742
  	struct rme32 *rme32 = snd_kcontrol_chip(kcontrol);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1743
1744
1745
1746
1747
1748
1749
1750
1751
1752
  	int change;
  	u32 val;
  
  	val = snd_rme32_convert_from_aes(&ucontrol->value.iec958);
  	spin_lock_irq(&rme32->lock);
  	change = val != rme32->wcreg_spdif;
  	rme32->wcreg_spdif = val;
  	spin_unlock_irq(&rme32->lock);
  	return change;
  }
017ce8023   Takashi Iwai   [ALSA] Remove xxx...
1753
1754
  static int snd_rme32_control_spdif_stream_info(struct snd_kcontrol *kcontrol,
  					       struct snd_ctl_elem_info *uinfo)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1755
1756
1757
1758
1759
  {
  	uinfo->type = SNDRV_CTL_ELEM_TYPE_IEC958;
  	uinfo->count = 1;
  	return 0;
  }
017ce8023   Takashi Iwai   [ALSA] Remove xxx...
1760
1761
  static int snd_rme32_control_spdif_stream_get(struct snd_kcontrol *kcontrol,
  					      struct snd_ctl_elem_value *
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1762
1763
  					      ucontrol)
  {
017ce8023   Takashi Iwai   [ALSA] Remove xxx...
1764
  	struct rme32 *rme32 = snd_kcontrol_chip(kcontrol);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1765
1766
1767
1768
1769
  
  	snd_rme32_convert_to_aes(&ucontrol->value.iec958,
  				 rme32->wcreg_spdif_stream);
  	return 0;
  }
017ce8023   Takashi Iwai   [ALSA] Remove xxx...
1770
1771
  static int snd_rme32_control_spdif_stream_put(struct snd_kcontrol *kcontrol,
  					      struct snd_ctl_elem_value *
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1772
1773
  					      ucontrol)
  {
017ce8023   Takashi Iwai   [ALSA] Remove xxx...
1774
  	struct rme32 *rme32 = snd_kcontrol_chip(kcontrol);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1775
1776
1777
1778
1779
1780
1781
1782
1783
1784
1785
1786
1787
  	int change;
  	u32 val;
  
  	val = snd_rme32_convert_from_aes(&ucontrol->value.iec958);
  	spin_lock_irq(&rme32->lock);
  	change = val != rme32->wcreg_spdif_stream;
  	rme32->wcreg_spdif_stream = val;
  	rme32->wcreg &= ~(RME32_WCR_PRO | RME32_WCR_EMP);
  	rme32->wcreg |= val;
  	writel(rme32->wcreg, rme32->iobase + RME32_IO_CONTROL_REGISTER);
  	spin_unlock_irq(&rme32->lock);
  	return change;
  }
017ce8023   Takashi Iwai   [ALSA] Remove xxx...
1788
1789
  static int snd_rme32_control_spdif_mask_info(struct snd_kcontrol *kcontrol,
  					     struct snd_ctl_elem_info *uinfo)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1790
1791
1792
1793
1794
  {
  	uinfo->type = SNDRV_CTL_ELEM_TYPE_IEC958;
  	uinfo->count = 1;
  	return 0;
  }
017ce8023   Takashi Iwai   [ALSA] Remove xxx...
1795
1796
  static int snd_rme32_control_spdif_mask_get(struct snd_kcontrol *kcontrol,
  					    struct snd_ctl_elem_value *
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1797
1798
1799
1800
1801
  					    ucontrol)
  {
  	ucontrol->value.iec958.status[0] = kcontrol->private_value;
  	return 0;
  }
017ce8023   Takashi Iwai   [ALSA] Remove xxx...
1802
  static struct snd_kcontrol_new snd_rme32_controls[] = {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1803
1804
1805
1806
1807
1808
1809
1810
1811
1812
1813
1814
1815
1816
1817
1818
1819
  	{
  		.iface = SNDRV_CTL_ELEM_IFACE_PCM,
  		.name =	SNDRV_CTL_NAME_IEC958("", PLAYBACK, DEFAULT),
  		.info =	snd_rme32_control_spdif_info,
  		.get =	snd_rme32_control_spdif_get,
  		.put =	snd_rme32_control_spdif_put
  	},
  	{
  		.access = SNDRV_CTL_ELEM_ACCESS_READWRITE | SNDRV_CTL_ELEM_ACCESS_INACTIVE,
  		.iface = SNDRV_CTL_ELEM_IFACE_PCM,
  		.name =	SNDRV_CTL_NAME_IEC958("", PLAYBACK, PCM_STREAM),
  		.info =	snd_rme32_control_spdif_stream_info,
  		.get =	snd_rme32_control_spdif_stream_get,
  		.put =	snd_rme32_control_spdif_stream_put
  	},
  	{
  		.access = SNDRV_CTL_ELEM_ACCESS_READ,
67ed4161f   Clemens Ladisch   [ALSA] sound - fi...
1820
  		.iface = SNDRV_CTL_ELEM_IFACE_PCM,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1821
1822
1823
1824
1825
1826
1827
  		.name =	SNDRV_CTL_NAME_IEC958("", PLAYBACK, CON_MASK),
  		.info =	snd_rme32_control_spdif_mask_info,
  		.get =	snd_rme32_control_spdif_mask_get,
  		.private_value = IEC958_AES0_PROFESSIONAL | IEC958_AES0_CON_EMPHASIS
  	},
  	{
  		.access = SNDRV_CTL_ELEM_ACCESS_READ,
67ed4161f   Clemens Ladisch   [ALSA] sound - fi...
1828
  		.iface = SNDRV_CTL_ELEM_IFACE_PCM,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1829
1830
1831
1832
1833
1834
1835
1836
1837
1838
1839
1840
1841
1842
1843
1844
1845
1846
1847
1848
1849
1850
1851
1852
1853
1854
1855
  		.name =	SNDRV_CTL_NAME_IEC958("", PLAYBACK, PRO_MASK),
  		.info =	snd_rme32_control_spdif_mask_info,
  		.get =	snd_rme32_control_spdif_mask_get,
  		.private_value = IEC958_AES0_PROFESSIONAL | IEC958_AES0_PRO_EMPHASIS
  	},
  	{
  		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
  		.name =	"Input Connector",
  		.info =	snd_rme32_info_inputtype_control,
  		.get =	snd_rme32_get_inputtype_control,
  		.put =	snd_rme32_put_inputtype_control
  	},
  	{
  		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
  		.name =	"Loopback Input",
  		.info =	snd_rme32_info_loopback_control,
  		.get =	snd_rme32_get_loopback_control,
  		.put =	snd_rme32_put_loopback_control
  	},
  	{
  		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
  		.name =	"Sample Clock Source",
  		.info =	snd_rme32_info_clockmode_control,
  		.get =	snd_rme32_get_clockmode_control,
  		.put =	snd_rme32_put_clockmode_control
  	}
  };
017ce8023   Takashi Iwai   [ALSA] Remove xxx...
1856
  static int snd_rme32_create_switches(struct snd_card *card, struct rme32 * rme32)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1857
1858
  {
  	int idx, err;
017ce8023   Takashi Iwai   [ALSA] Remove xxx...
1859
  	struct snd_kcontrol *kctl;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1860
1861
1862
1863
1864
1865
1866
1867
1868
1869
1870
1871
1872
1873
  
  	for (idx = 0; idx < (int)ARRAY_SIZE(snd_rme32_controls); idx++) {
  		if ((err = snd_ctl_add(card, kctl = snd_ctl_new1(&snd_rme32_controls[idx], rme32))) < 0)
  			return err;
  		if (idx == 1)	/* IEC958 (S/PDIF) Stream */
  			rme32->spdif_ctl = kctl;
  	}
  
  	return 0;
  }
  
  /*
   * Card initialisation
   */
017ce8023   Takashi Iwai   [ALSA] Remove xxx...
1874
  static void snd_rme32_card_free(struct snd_card *card)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1875
1876
1877
  {
  	snd_rme32_free(card->private_data);
  }
e23e7a143   Bill Pemberton   ALSA: pci: remove...
1878
  static int
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1879
1880
1881
  snd_rme32_probe(struct pci_dev *pci, const struct pci_device_id *pci_id)
  {
  	static int dev;
017ce8023   Takashi Iwai   [ALSA] Remove xxx...
1882
1883
  	struct rme32 *rme32;
  	struct snd_card *card;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1884
1885
1886
1887
1888
1889
1890
1891
1892
  	int err;
  
  	if (dev >= SNDRV_CARDS) {
  		return -ENODEV;
  	}
  	if (!enable[dev]) {
  		dev++;
  		return -ENOENT;
  	}
60c5772b5   Takashi Iwai   ALSA: pci: Conver...
1893
1894
  	err = snd_card_new(&pci->dev, index[dev], id[dev], THIS_MODULE,
  			   sizeof(struct rme32), &card);
e58de7baf   Takashi Iwai   ALSA: Convert to ...
1895
1896
  	if (err < 0)
  		return err;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1897
  	card->private_free = snd_rme32_card_free;
017ce8023   Takashi Iwai   [ALSA] Remove xxx...
1898
  	rme32 = (struct rme32 *) card->private_data;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1899
1900
  	rme32->card = card;
  	rme32->pci = pci;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1901
1902
1903
1904
1905
1906
1907
1908
1909
          if (fullduplex[dev])
  		rme32->fullduplex_mode = 1;
  	if ((err = snd_rme32_create(rme32)) < 0) {
  		snd_card_free(card);
  		return err;
  	}
  
  	strcpy(card->driver, "Digi32");
  	switch (rme32->pci->device) {
8b7fc4214   Roland Dreier   [PATCH] add PCI I...
1910
  	case PCI_DEVICE_ID_RME_DIGI32:
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1911
1912
  		strcpy(card->shortname, "RME Digi32");
  		break;
8b7fc4214   Roland Dreier   [PATCH] add PCI I...
1913
  	case PCI_DEVICE_ID_RME_DIGI32_8:
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1914
1915
  		strcpy(card->shortname, "RME Digi32/8");
  		break;
8b7fc4214   Roland Dreier   [PATCH] add PCI I...
1916
  	case PCI_DEVICE_ID_RME_DIGI32_PRO:
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1917
1918
1919
1920
1921
1922
1923
1924
1925
1926
1927
1928
1929
1930
  		strcpy(card->shortname, "RME Digi32 PRO");
  		break;
  	}
  	sprintf(card->longname, "%s (Rev. %d) at 0x%lx, irq %d",
  		card->shortname, rme32->rev, rme32->port, rme32->irq);
  
  	if ((err = snd_card_register(card)) < 0) {
  		snd_card_free(card);
  		return err;
  	}
  	pci_set_drvdata(pci, card);
  	dev++;
  	return 0;
  }
e23e7a143   Bill Pemberton   ALSA: pci: remove...
1931
  static void snd_rme32_remove(struct pci_dev *pci)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1932
1933
  {
  	snd_card_free(pci_get_drvdata(pci));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1934
  }
e9f66d9b9   Takashi Iwai   ALSA: pci: clean ...
1935
  static struct pci_driver rme32_driver = {
3733e424c   Takashi Iwai   ALSA: Use KBUILD_...
1936
  	.name =		KBUILD_MODNAME,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1937
1938
  	.id_table =	snd_rme32_ids,
  	.probe =	snd_rme32_probe,
e23e7a143   Bill Pemberton   ALSA: pci: remove...
1939
  	.remove =	snd_rme32_remove,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1940
  };
e9f66d9b9   Takashi Iwai   ALSA: pci: clean ...
1941
  module_pci_driver(rme32_driver);