blob: 4ebd283e56a3cbf0471362ee9c87cbf5577db9c9 [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/*
2 * ALSA driver for RME Hammerfall DSP audio interface(s)
3 *
4 * Copyright (c) 2002 Paul Davis
5 * Marcus Andersson
6 * Thomas Charbonnel
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
21 *
22 */
23
Linus Torvalds1da177e2005-04-16 15:20:36 -070024#include <linux/init.h>
25#include <linux/delay.h>
26#include <linux/interrupt.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070027#include <linux/pci.h>
28#include <linux/firmware.h>
Paul Gortmaker65a77212011-07-15 13:13:37 -040029#include <linux/module.h>
Takashi Iwai3f7440a2009-06-05 17:40:04 +020030#include <linux/math64.h>
Takashi Iwai82329322012-11-22 21:19:18 +010031#include <linux/vmalloc.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070032
33#include <sound/core.h>
34#include <sound/control.h>
35#include <sound/pcm.h>
36#include <sound/info.h>
37#include <sound/asoundef.h>
38#include <sound/rawmidi.h>
39#include <sound/hwdep.h>
40#include <sound/initval.h>
41#include <sound/hdsp.h>
42
43#include <asm/byteorder.h>
44#include <asm/current.h>
45#include <asm/io.h>
46
47static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX; /* Index 0-MAX */
48static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR; /* ID for this card */
Rusty Russella67ff6a2011-12-15 13:49:36 +103049static bool enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE_PNP; /* Enable this card */
Linus Torvalds1da177e2005-04-16 15:20:36 -070050
51module_param_array(index, int, NULL, 0444);
52MODULE_PARM_DESC(index, "Index value for RME Hammerfall DSP interface.");
53module_param_array(id, charp, NULL, 0444);
54MODULE_PARM_DESC(id, "ID string for RME Hammerfall DSP interface.");
55module_param_array(enable, bool, NULL, 0444);
56MODULE_PARM_DESC(enable, "Enable/disable specific Hammerfall DSP soundcards.");
57MODULE_AUTHOR("Paul Davis <paul@linuxaudiosystems.com>, Marcus Andersson, Thomas Charbonnel <thomas@undata.org>");
58MODULE_DESCRIPTION("RME Hammerfall DSP");
59MODULE_LICENSE("GPL");
60MODULE_SUPPORTED_DEVICE("{{RME Hammerfall-DSP},"
61 "{RME HDSP-9652},"
62 "{RME HDSP-9632}}");
Florian Faber28b26e12010-12-01 12:14:47 +010063MODULE_FIRMWARE("rpm_firmware.bin");
Clemens Ladisch7e0af292007-05-03 17:59:54 +020064MODULE_FIRMWARE("multiface_firmware.bin");
65MODULE_FIRMWARE("multiface_firmware_rev11.bin");
66MODULE_FIRMWARE("digiface_firmware.bin");
67MODULE_FIRMWARE("digiface_firmware_rev11.bin");
Linus Torvalds1da177e2005-04-16 15:20:36 -070068
69#define HDSP_MAX_CHANNELS 26
70#define HDSP_MAX_DS_CHANNELS 14
71#define HDSP_MAX_QS_CHANNELS 8
72#define DIGIFACE_SS_CHANNELS 26
73#define DIGIFACE_DS_CHANNELS 14
74#define MULTIFACE_SS_CHANNELS 18
75#define MULTIFACE_DS_CHANNELS 14
76#define H9652_SS_CHANNELS 26
77#define H9652_DS_CHANNELS 14
78/* This does not include possible Analog Extension Boards
79 AEBs are detected at card initialization
80*/
81#define H9632_SS_CHANNELS 12
82#define H9632_DS_CHANNELS 8
83#define H9632_QS_CHANNELS 4
Florian Faber28b26e12010-12-01 12:14:47 +010084#define RPM_CHANNELS 6
Linus Torvalds1da177e2005-04-16 15:20:36 -070085
86/* Write registers. These are defined as byte-offsets from the iobase value.
87 */
88#define HDSP_resetPointer 0
Remy Brunod7923b22006-10-17 12:41:56 +020089#define HDSP_freqReg 0
Linus Torvalds1da177e2005-04-16 15:20:36 -070090#define HDSP_outputBufferAddress 32
91#define HDSP_inputBufferAddress 36
92#define HDSP_controlRegister 64
93#define HDSP_interruptConfirmation 96
94#define HDSP_outputEnable 128
95#define HDSP_control2Reg 256
96#define HDSP_midiDataOut0 352
97#define HDSP_midiDataOut1 356
98#define HDSP_fifoData 368
99#define HDSP_inputEnable 384
100
101/* Read registers. These are defined as byte-offsets from the iobase value
102 */
103
104#define HDSP_statusRegister 0
105#define HDSP_timecode 128
106#define HDSP_status2Register 192
Linus Torvalds1da177e2005-04-16 15:20:36 -0700107#define HDSP_midiDataIn0 360
108#define HDSP_midiDataIn1 364
109#define HDSP_midiStatusOut0 384
110#define HDSP_midiStatusOut1 388
111#define HDSP_midiStatusIn0 392
112#define HDSP_midiStatusIn1 396
113#define HDSP_fifoStatus 400
114
115/* the meters are regular i/o-mapped registers, but offset
116 considerably from the rest. the peak registers are reset
Tim Blechmannf9ffc5d2009-02-20 19:38:16 +0100117 when read; the least-significant 4 bits are full-scale counters;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700118 the actual peak value is in the most-significant 24 bits.
119*/
120
121#define HDSP_playbackPeakLevel 4096 /* 26 * 32 bit values */
122#define HDSP_inputPeakLevel 4224 /* 26 * 32 bit values */
123#define HDSP_outputPeakLevel 4352 /* (26+2) * 32 bit values */
124#define HDSP_playbackRmsLevel 4612 /* 26 * 64 bit values */
125#define HDSP_inputRmsLevel 4868 /* 26 * 64 bit values */
126
127
128/* This is for H9652 cards
129 Peak values are read downward from the base
130 Rms values are read upward
131 There are rms values for the outputs too
132 26*3 values are read in ss mode
133 14*3 in ds mode, with no gap between values
134*/
Tim Blechmannf9ffc5d2009-02-20 19:38:16 +0100135#define HDSP_9652_peakBase 7164
Linus Torvalds1da177e2005-04-16 15:20:36 -0700136#define HDSP_9652_rmsBase 4096
137
138/* c.f. the hdsp_9632_meters_t struct */
139#define HDSP_9632_metersBase 4096
140
141#define HDSP_IO_EXTENT 7168
142
143/* control2 register bits */
144
145#define HDSP_TMS 0x01
146#define HDSP_TCK 0x02
147#define HDSP_TDI 0x04
148#define HDSP_JTAG 0x08
149#define HDSP_PWDN 0x10
150#define HDSP_PROGRAM 0x020
151#define HDSP_CONFIG_MODE_0 0x040
152#define HDSP_CONFIG_MODE_1 0x080
Adrian Knotha3466862011-10-27 21:57:53 +0200153#define HDSP_VERSION_BIT (0x100 | HDSP_S_LOAD)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700154#define HDSP_BIGENDIAN_MODE 0x200
155#define HDSP_RD_MULTIPLE 0x400
156#define HDSP_9652_ENABLE_MIXER 0x800
Adrian Knoth0c2bc7c2013-01-15 18:52:20 +0100157#define HDSP_S200 0x800
158#define HDSP_S300 (0x100 | HDSP_S200) /* dummy, purpose of 0x100 unknown */
159#define HDSP_CYCLIC_MODE 0x1000
Linus Torvalds1da177e2005-04-16 15:20:36 -0700160#define HDSP_TDO 0x10000000
161
Adrian Knoth0c2bc7c2013-01-15 18:52:20 +0100162#define HDSP_S_PROGRAM (HDSP_CYCLIC_MODE|HDSP_PROGRAM|HDSP_CONFIG_MODE_0)
163#define HDSP_S_LOAD (HDSP_CYCLIC_MODE|HDSP_PROGRAM|HDSP_CONFIG_MODE_1)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700164
165/* Control Register bits */
166
167#define HDSP_Start (1<<0) /* start engine */
168#define HDSP_Latency0 (1<<1) /* buffer size = 2^n where n is defined by Latency{2,1,0} */
169#define HDSP_Latency1 (1<<2) /* [ see above ] */
170#define HDSP_Latency2 (1<<3) /* [ see above ] */
171#define HDSP_ClockModeMaster (1<<4) /* 1=Master, 0=Slave/Autosync */
172#define HDSP_AudioInterruptEnable (1<<5) /* what do you think ? */
173#define HDSP_Frequency0 (1<<6) /* 0=44.1kHz/88.2kHz/176.4kHz 1=48kHz/96kHz/192kHz */
174#define HDSP_Frequency1 (1<<7) /* 0=32kHz/64kHz/128kHz */
175#define HDSP_DoubleSpeed (1<<8) /* 0=normal speed, 1=double speed */
176#define HDSP_SPDIFProfessional (1<<9) /* 0=consumer, 1=professional */
177#define HDSP_SPDIFEmphasis (1<<10) /* 0=none, 1=on */
178#define HDSP_SPDIFNonAudio (1<<11) /* 0=off, 1=on */
179#define HDSP_SPDIFOpticalOut (1<<12) /* 1=use 1st ADAT connector for SPDIF, 0=do not */
Tim Blechmannf9ffc5d2009-02-20 19:38:16 +0100180#define HDSP_SyncRef2 (1<<13)
181#define HDSP_SPDIFInputSelect0 (1<<14)
182#define HDSP_SPDIFInputSelect1 (1<<15)
183#define HDSP_SyncRef0 (1<<16)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700184#define HDSP_SyncRef1 (1<<17)
Tim Blechmannf9ffc5d2009-02-20 19:38:16 +0100185#define HDSP_AnalogExtensionBoard (1<<18) /* For H9632 cards */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700186#define HDSP_XLRBreakoutCable (1<<20) /* For H9632 cards */
187#define HDSP_Midi0InterruptEnable (1<<22)
188#define HDSP_Midi1InterruptEnable (1<<23)
189#define HDSP_LineOut (1<<24)
190#define HDSP_ADGain0 (1<<25) /* From here : H9632 specific */
191#define HDSP_ADGain1 (1<<26)
192#define HDSP_DAGain0 (1<<27)
193#define HDSP_DAGain1 (1<<28)
194#define HDSP_PhoneGain0 (1<<29)
195#define HDSP_PhoneGain1 (1<<30)
196#define HDSP_QuadSpeed (1<<31)
197
Florian Faber28b26e12010-12-01 12:14:47 +0100198/* RPM uses some of the registers for special purposes */
199#define HDSP_RPM_Inp12 0x04A00
200#define HDSP_RPM_Inp12_Phon_6dB 0x00800 /* Dolby */
201#define HDSP_RPM_Inp12_Phon_0dB 0x00000 /* .. */
202#define HDSP_RPM_Inp12_Phon_n6dB 0x04000 /* inp_0 */
203#define HDSP_RPM_Inp12_Line_0dB 0x04200 /* Dolby+PRO */
204#define HDSP_RPM_Inp12_Line_n6dB 0x00200 /* PRO */
205
206#define HDSP_RPM_Inp34 0x32000
207#define HDSP_RPM_Inp34_Phon_6dB 0x20000 /* SyncRef1 */
208#define HDSP_RPM_Inp34_Phon_0dB 0x00000 /* .. */
209#define HDSP_RPM_Inp34_Phon_n6dB 0x02000 /* SyncRef2 */
210#define HDSP_RPM_Inp34_Line_0dB 0x30000 /* SyncRef1+SyncRef0 */
211#define HDSP_RPM_Inp34_Line_n6dB 0x10000 /* SyncRef0 */
212
213#define HDSP_RPM_Bypass 0x01000
214
215#define HDSP_RPM_Disconnect 0x00001
216
Linus Torvalds1da177e2005-04-16 15:20:36 -0700217#define HDSP_ADGainMask (HDSP_ADGain0|HDSP_ADGain1)
218#define HDSP_ADGainMinus10dBV HDSP_ADGainMask
219#define HDSP_ADGainPlus4dBu (HDSP_ADGain0)
220#define HDSP_ADGainLowGain 0
221
222#define HDSP_DAGainMask (HDSP_DAGain0|HDSP_DAGain1)
223#define HDSP_DAGainHighGain HDSP_DAGainMask
224#define HDSP_DAGainPlus4dBu (HDSP_DAGain0)
225#define HDSP_DAGainMinus10dBV 0
226
227#define HDSP_PhoneGainMask (HDSP_PhoneGain0|HDSP_PhoneGain1)
228#define HDSP_PhoneGain0dB HDSP_PhoneGainMask
229#define HDSP_PhoneGainMinus6dB (HDSP_PhoneGain0)
230#define HDSP_PhoneGainMinus12dB 0
231
232#define HDSP_LatencyMask (HDSP_Latency0|HDSP_Latency1|HDSP_Latency2)
233#define HDSP_FrequencyMask (HDSP_Frequency0|HDSP_Frequency1|HDSP_DoubleSpeed|HDSP_QuadSpeed)
234
235#define HDSP_SPDIFInputMask (HDSP_SPDIFInputSelect0|HDSP_SPDIFInputSelect1)
236#define HDSP_SPDIFInputADAT1 0
237#define HDSP_SPDIFInputCoaxial (HDSP_SPDIFInputSelect0)
238#define HDSP_SPDIFInputCdrom (HDSP_SPDIFInputSelect1)
239#define HDSP_SPDIFInputAES (HDSP_SPDIFInputSelect0|HDSP_SPDIFInputSelect1)
240
241#define HDSP_SyncRefMask (HDSP_SyncRef0|HDSP_SyncRef1|HDSP_SyncRef2)
242#define HDSP_SyncRef_ADAT1 0
243#define HDSP_SyncRef_ADAT2 (HDSP_SyncRef0)
244#define HDSP_SyncRef_ADAT3 (HDSP_SyncRef1)
245#define HDSP_SyncRef_SPDIF (HDSP_SyncRef0|HDSP_SyncRef1)
246#define HDSP_SyncRef_WORD (HDSP_SyncRef2)
247#define HDSP_SyncRef_ADAT_SYNC (HDSP_SyncRef0|HDSP_SyncRef2)
248
249/* Sample Clock Sources */
250
251#define HDSP_CLOCK_SOURCE_AUTOSYNC 0
252#define HDSP_CLOCK_SOURCE_INTERNAL_32KHZ 1
253#define HDSP_CLOCK_SOURCE_INTERNAL_44_1KHZ 2
254#define HDSP_CLOCK_SOURCE_INTERNAL_48KHZ 3
255#define HDSP_CLOCK_SOURCE_INTERNAL_64KHZ 4
256#define HDSP_CLOCK_SOURCE_INTERNAL_88_2KHZ 5
257#define HDSP_CLOCK_SOURCE_INTERNAL_96KHZ 6
258#define HDSP_CLOCK_SOURCE_INTERNAL_128KHZ 7
259#define HDSP_CLOCK_SOURCE_INTERNAL_176_4KHZ 8
260#define HDSP_CLOCK_SOURCE_INTERNAL_192KHZ 9
261
262/* Preferred sync reference choices - used by "pref_sync_ref" control switch */
263
264#define HDSP_SYNC_FROM_WORD 0
265#define HDSP_SYNC_FROM_SPDIF 1
266#define HDSP_SYNC_FROM_ADAT1 2
267#define HDSP_SYNC_FROM_ADAT_SYNC 3
268#define HDSP_SYNC_FROM_ADAT2 4
269#define HDSP_SYNC_FROM_ADAT3 5
270
271/* SyncCheck status */
272
273#define HDSP_SYNC_CHECK_NO_LOCK 0
274#define HDSP_SYNC_CHECK_LOCK 1
275#define HDSP_SYNC_CHECK_SYNC 2
276
277/* AutoSync references - used by "autosync_ref" control switch */
278
279#define HDSP_AUTOSYNC_FROM_WORD 0
280#define HDSP_AUTOSYNC_FROM_ADAT_SYNC 1
281#define HDSP_AUTOSYNC_FROM_SPDIF 2
282#define HDSP_AUTOSYNC_FROM_NONE 3
283#define HDSP_AUTOSYNC_FROM_ADAT1 4
284#define HDSP_AUTOSYNC_FROM_ADAT2 5
285#define HDSP_AUTOSYNC_FROM_ADAT3 6
286
287/* Possible sources of S/PDIF input */
288
289#define HDSP_SPDIFIN_OPTICAL 0 /* optical (ADAT1) */
290#define HDSP_SPDIFIN_COAXIAL 1 /* coaxial (RCA) */
291#define HDSP_SPDIFIN_INTERNAL 2 /* internal (CDROM) */
292#define HDSP_SPDIFIN_AES 3 /* xlr for H9632 (AES)*/
293
294#define HDSP_Frequency32KHz HDSP_Frequency0
295#define HDSP_Frequency44_1KHz HDSP_Frequency1
296#define HDSP_Frequency48KHz (HDSP_Frequency1|HDSP_Frequency0)
297#define HDSP_Frequency64KHz (HDSP_DoubleSpeed|HDSP_Frequency0)
298#define HDSP_Frequency88_2KHz (HDSP_DoubleSpeed|HDSP_Frequency1)
299#define HDSP_Frequency96KHz (HDSP_DoubleSpeed|HDSP_Frequency1|HDSP_Frequency0)
300/* For H9632 cards */
301#define HDSP_Frequency128KHz (HDSP_QuadSpeed|HDSP_DoubleSpeed|HDSP_Frequency0)
302#define HDSP_Frequency176_4KHz (HDSP_QuadSpeed|HDSP_DoubleSpeed|HDSP_Frequency1)
303#define HDSP_Frequency192KHz (HDSP_QuadSpeed|HDSP_DoubleSpeed|HDSP_Frequency1|HDSP_Frequency0)
Julian Cablee4b60882007-03-19 11:44:40 +0100304/* RME says n = 104857600000000, but in the windows MADI driver, I see:
305 return 104857600000000 / rate; // 100 MHz
306 return 110100480000000 / rate; // 105 MHz
307*/
308#define DDS_NUMERATOR 104857600000000ULL; /* = 2^20 * 10^8 */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700309
310#define hdsp_encode_latency(x) (((x)<<1) & HDSP_LatencyMask)
311#define hdsp_decode_latency(x) (((x) & HDSP_LatencyMask)>>1)
312
313#define hdsp_encode_spdif_in(x) (((x)&0x3)<<14)
314#define hdsp_decode_spdif_in(x) (((x)>>14)&0x3)
315
316/* Status Register bits */
317
318#define HDSP_audioIRQPending (1<<0)
319#define HDSP_Lock2 (1<<1) /* this is for Digiface and H9652 */
320#define HDSP_spdifFrequency3 HDSP_Lock2 /* this is for H9632 only */
321#define HDSP_Lock1 (1<<2)
322#define HDSP_Lock0 (1<<3)
323#define HDSP_SPDIFSync (1<<4)
324#define HDSP_TimecodeLock (1<<5)
325#define HDSP_BufferPositionMask 0x000FFC0 /* Bit 6..15 : h/w buffer pointer */
326#define HDSP_Sync2 (1<<16)
327#define HDSP_Sync1 (1<<17)
328#define HDSP_Sync0 (1<<18)
329#define HDSP_DoubleSpeedStatus (1<<19)
330#define HDSP_ConfigError (1<<20)
331#define HDSP_DllError (1<<21)
332#define HDSP_spdifFrequency0 (1<<22)
333#define HDSP_spdifFrequency1 (1<<23)
334#define HDSP_spdifFrequency2 (1<<24)
335#define HDSP_SPDIFErrorFlag (1<<25)
336#define HDSP_BufferID (1<<26)
337#define HDSP_TimecodeSync (1<<27)
338#define HDSP_AEBO (1<<28) /* H9632 specific Analog Extension Boards */
339#define HDSP_AEBI (1<<29) /* 0 = present, 1 = absent */
Tim Blechmannf9ffc5d2009-02-20 19:38:16 +0100340#define HDSP_midi0IRQPending (1<<30)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700341#define HDSP_midi1IRQPending (1<<31)
342
343#define HDSP_spdifFrequencyMask (HDSP_spdifFrequency0|HDSP_spdifFrequency1|HDSP_spdifFrequency2)
Remy Bruno47ba97f2008-02-22 17:57:02 +0100344#define HDSP_spdifFrequencyMask_9632 (HDSP_spdifFrequency0|\
345 HDSP_spdifFrequency1|\
346 HDSP_spdifFrequency2|\
347 HDSP_spdifFrequency3)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700348
349#define HDSP_spdifFrequency32KHz (HDSP_spdifFrequency0)
350#define HDSP_spdifFrequency44_1KHz (HDSP_spdifFrequency1)
351#define HDSP_spdifFrequency48KHz (HDSP_spdifFrequency0|HDSP_spdifFrequency1)
352
353#define HDSP_spdifFrequency64KHz (HDSP_spdifFrequency2)
354#define HDSP_spdifFrequency88_2KHz (HDSP_spdifFrequency0|HDSP_spdifFrequency2)
355#define HDSP_spdifFrequency96KHz (HDSP_spdifFrequency2|HDSP_spdifFrequency1)
356
357/* This is for H9632 cards */
Remy Bruno47ba97f2008-02-22 17:57:02 +0100358#define HDSP_spdifFrequency128KHz (HDSP_spdifFrequency0|\
359 HDSP_spdifFrequency1|\
360 HDSP_spdifFrequency2)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700361#define HDSP_spdifFrequency176_4KHz HDSP_spdifFrequency3
362#define HDSP_spdifFrequency192KHz (HDSP_spdifFrequency3|HDSP_spdifFrequency0)
363
364/* Status2 Register bits */
365
366#define HDSP_version0 (1<<0)
367#define HDSP_version1 (1<<1)
368#define HDSP_version2 (1<<2)
369#define HDSP_wc_lock (1<<3)
370#define HDSP_wc_sync (1<<4)
371#define HDSP_inp_freq0 (1<<5)
372#define HDSP_inp_freq1 (1<<6)
373#define HDSP_inp_freq2 (1<<7)
374#define HDSP_SelSyncRef0 (1<<8)
375#define HDSP_SelSyncRef1 (1<<9)
376#define HDSP_SelSyncRef2 (1<<10)
377
378#define HDSP_wc_valid (HDSP_wc_lock|HDSP_wc_sync)
379
380#define HDSP_systemFrequencyMask (HDSP_inp_freq0|HDSP_inp_freq1|HDSP_inp_freq2)
381#define HDSP_systemFrequency32 (HDSP_inp_freq0)
382#define HDSP_systemFrequency44_1 (HDSP_inp_freq1)
383#define HDSP_systemFrequency48 (HDSP_inp_freq0|HDSP_inp_freq1)
384#define HDSP_systemFrequency64 (HDSP_inp_freq2)
385#define HDSP_systemFrequency88_2 (HDSP_inp_freq0|HDSP_inp_freq2)
386#define HDSP_systemFrequency96 (HDSP_inp_freq1|HDSP_inp_freq2)
387/* FIXME : more values for 9632 cards ? */
388
389#define HDSP_SelSyncRefMask (HDSP_SelSyncRef0|HDSP_SelSyncRef1|HDSP_SelSyncRef2)
390#define HDSP_SelSyncRef_ADAT1 0
391#define HDSP_SelSyncRef_ADAT2 (HDSP_SelSyncRef0)
392#define HDSP_SelSyncRef_ADAT3 (HDSP_SelSyncRef1)
393#define HDSP_SelSyncRef_SPDIF (HDSP_SelSyncRef0|HDSP_SelSyncRef1)
394#define HDSP_SelSyncRef_WORD (HDSP_SelSyncRef2)
395#define HDSP_SelSyncRef_ADAT_SYNC (HDSP_SelSyncRef0|HDSP_SelSyncRef2)
396
397/* Card state flags */
398
399#define HDSP_InitializationComplete (1<<0)
400#define HDSP_FirmwareLoaded (1<<1)
401#define HDSP_FirmwareCached (1<<2)
402
403/* FIFO wait times, defined in terms of 1/10ths of msecs */
404
405#define HDSP_LONG_WAIT 5000
406#define HDSP_SHORT_WAIT 30
407
408#define UNITY_GAIN 32768
409#define MINUS_INFINITY_GAIN 0
410
Linus Torvalds1da177e2005-04-16 15:20:36 -0700411/* the size of a substream (1 mono data stream) */
412
413#define HDSP_CHANNEL_BUFFER_SAMPLES (16*1024)
414#define HDSP_CHANNEL_BUFFER_BYTES (4*HDSP_CHANNEL_BUFFER_SAMPLES)
415
416/* the size of the area we need to allocate for DMA transfers. the
Tim Blechmannf9ffc5d2009-02-20 19:38:16 +0100417 size is the same regardless of the number of channels - the
Linus Torvalds1da177e2005-04-16 15:20:36 -0700418 Multiface still uses the same memory area.
419
420 Note that we allocate 1 more channel than is apparently needed
421 because the h/w seems to write 1 byte beyond the end of the last
422 page. Sigh.
423*/
424
425#define HDSP_DMA_AREA_BYTES ((HDSP_MAX_CHANNELS+1) * HDSP_CHANNEL_BUFFER_BYTES)
426#define HDSP_DMA_AREA_KILOBYTES (HDSP_DMA_AREA_BYTES/1024)
427
Takashi Iwai90caaef2012-11-22 16:55:11 +0100428#define HDSP_FIRMWARE_SIZE (24413 * 4)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700429
Takashi Iwai55e957d2005-11-17 14:52:13 +0100430struct hdsp_9632_meters {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700431 u32 input_peak[16];
432 u32 playback_peak[16];
433 u32 output_peak[16];
434 u32 xxx_peak[16];
435 u32 padding[64];
436 u32 input_rms_low[16];
437 u32 playback_rms_low[16];
438 u32 output_rms_low[16];
439 u32 xxx_rms_low[16];
440 u32 input_rms_high[16];
441 u32 playback_rms_high[16];
442 u32 output_rms_high[16];
443 u32 xxx_rms_high[16];
444};
445
Takashi Iwai55e957d2005-11-17 14:52:13 +0100446struct hdsp_midi {
447 struct hdsp *hdsp;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700448 int id;
Takashi Iwai55e957d2005-11-17 14:52:13 +0100449 struct snd_rawmidi *rmidi;
450 struct snd_rawmidi_substream *input;
451 struct snd_rawmidi_substream *output;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700452 char istimer; /* timer in use */
453 struct timer_list timer;
454 spinlock_t lock;
455 int pending;
456};
457
Takashi Iwai55e957d2005-11-17 14:52:13 +0100458struct hdsp {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700459 spinlock_t lock;
Takashi Iwai55e957d2005-11-17 14:52:13 +0100460 struct snd_pcm_substream *capture_substream;
461 struct snd_pcm_substream *playback_substream;
462 struct hdsp_midi midi[2];
Linus Torvalds1da177e2005-04-16 15:20:36 -0700463 struct tasklet_struct midi_tasklet;
464 int use_midi_tasklet;
465 int precise_ptr;
466 u32 control_register; /* cached value */
467 u32 control2_register; /* cached value */
468 u32 creg_spdif;
469 u32 creg_spdif_stream;
Takashi Iwaie3ea4d82005-07-04 18:12:39 +0200470 int clock_source_locked;
Florian Faber28b26e12010-12-01 12:14:47 +0100471 char *card_name; /* digiface/multiface/rpm */
Takashi Iwai55e957d2005-11-17 14:52:13 +0100472 enum HDSP_IO_Type io_type; /* ditto, but for code use */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700473 unsigned short firmware_rev;
474 unsigned short state; /* stores state bits */
Takashi Iwai90caaef2012-11-22 16:55:11 +0100475 const struct firmware *firmware;
476 u32 *fw_uploaded;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700477 size_t period_bytes; /* guess what this is */
478 unsigned char max_channels;
479 unsigned char qs_in_channels; /* quad speed mode for H9632 */
480 unsigned char ds_in_channels;
481 unsigned char ss_in_channels; /* different for multiface/digiface */
Tim Blechmannf9ffc5d2009-02-20 19:38:16 +0100482 unsigned char qs_out_channels;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700483 unsigned char ds_out_channels;
484 unsigned char ss_out_channels;
485
486 struct snd_dma_buffer capture_dma_buf;
487 struct snd_dma_buffer playback_dma_buf;
488 unsigned char *capture_buffer; /* suitably aligned address */
489 unsigned char *playback_buffer; /* suitably aligned address */
490
491 pid_t capture_pid;
492 pid_t playback_pid;
493 int running;
494 int system_sample_rate;
495 char *channel_map;
496 int dev;
497 int irq;
498 unsigned long port;
499 void __iomem *iobase;
Takashi Iwai55e957d2005-11-17 14:52:13 +0100500 struct snd_card *card;
501 struct snd_pcm *pcm;
502 struct snd_hwdep *hwdep;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700503 struct pci_dev *pci;
Takashi Iwai55e957d2005-11-17 14:52:13 +0100504 struct snd_kcontrol *spdif_ctl;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700505 unsigned short mixer_matrix[HDSP_MATRIX_MIXER_SIZE];
Remy Brunod7923b22006-10-17 12:41:56 +0200506 unsigned int dds_value; /* last value written to freq register */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700507};
508
509/* These tables map the ALSA channels 1..N to the channels that we
510 need to use in order to find the relevant channel buffer. RME
511 refer to this kind of mapping as between "the ADAT channel and
512 the DMA channel." We index it using the logical audio channel,
513 and the value is the DMA channel (i.e. channel buffer number)
514 where the data for that channel can be read/written from/to.
515*/
516
517static char channel_map_df_ss[HDSP_MAX_CHANNELS] = {
518 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17,
519 18, 19, 20, 21, 22, 23, 24, 25
520};
521
522static char channel_map_mf_ss[HDSP_MAX_CHANNELS] = { /* Multiface */
523 /* Analog */
Tim Blechmannf9ffc5d2009-02-20 19:38:16 +0100524 0, 1, 2, 3, 4, 5, 6, 7,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700525 /* ADAT 2 */
Tim Blechmannf9ffc5d2009-02-20 19:38:16 +0100526 16, 17, 18, 19, 20, 21, 22, 23,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700527 /* SPDIF */
528 24, 25,
529 -1, -1, -1, -1, -1, -1, -1, -1
530};
531
532static char channel_map_ds[HDSP_MAX_CHANNELS] = {
533 /* ADAT channels are remapped */
534 1, 3, 5, 7, 9, 11, 13, 15, 17, 19, 21, 23,
535 /* channels 12 and 13 are S/PDIF */
536 24, 25,
537 /* others don't exist */
538 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1
539};
540
541static char channel_map_H9632_ss[HDSP_MAX_CHANNELS] = {
542 /* ADAT channels */
543 0, 1, 2, 3, 4, 5, 6, 7,
544 /* SPDIF */
545 8, 9,
546 /* Analog */
Tim Blechmannf9ffc5d2009-02-20 19:38:16 +0100547 10, 11,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700548 /* AO4S-192 and AI4S-192 extension boards */
549 12, 13, 14, 15,
550 /* others don't exist */
Tim Blechmannf9ffc5d2009-02-20 19:38:16 +0100551 -1, -1, -1, -1, -1, -1, -1, -1,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700552 -1, -1
553};
554
555static char channel_map_H9632_ds[HDSP_MAX_CHANNELS] = {
556 /* ADAT */
557 1, 3, 5, 7,
558 /* SPDIF */
559 8, 9,
560 /* Analog */
Tim Blechmannf9ffc5d2009-02-20 19:38:16 +0100561 10, 11,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700562 /* AO4S-192 and AI4S-192 extension boards */
563 12, 13, 14, 15,
564 /* others don't exist */
565 -1, -1, -1, -1, -1, -1, -1, -1,
566 -1, -1, -1, -1, -1, -1
567};
568
569static char channel_map_H9632_qs[HDSP_MAX_CHANNELS] = {
570 /* ADAT is disabled in this mode */
571 /* SPDIF */
572 8, 9,
573 /* Analog */
574 10, 11,
575 /* AO4S-192 and AI4S-192 extension boards */
576 12, 13, 14, 15,
577 /* others don't exist */
578 -1, -1, -1, -1, -1, -1, -1, -1,
579 -1, -1, -1, -1, -1, -1, -1, -1,
580 -1, -1
581};
582
583static int snd_hammerfall_get_buffer(struct pci_dev *pci, struct snd_dma_buffer *dmab, size_t size)
584{
585 dmab->dev.type = SNDRV_DMA_TYPE_DEV;
586 dmab->dev.dev = snd_dma_pci_data(pci);
Takashi Iwaib6a96912005-05-30 18:27:03 +0200587 if (snd_dma_get_reserved_buf(dmab, snd_dma_pci_buf_id(pci))) {
588 if (dmab->bytes >= size)
589 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700590 }
Takashi Iwaib6a96912005-05-30 18:27:03 +0200591 if (snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, snd_dma_pci_data(pci),
592 size, dmab) < 0)
593 return -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700594 return 0;
595}
596
597static void snd_hammerfall_free_buffer(struct snd_dma_buffer *dmab, struct pci_dev *pci)
598{
Takashi Iwaib6a96912005-05-30 18:27:03 +0200599 if (dmab->area) {
600 dmab->dev.dev = NULL; /* make it anonymous */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700601 snd_dma_reserve_buf(dmab, snd_dma_pci_buf_id(pci));
Takashi Iwaib6a96912005-05-30 18:27:03 +0200602 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700603}
604
605
Alexey Dobriyancebe41d2010-02-06 00:21:03 +0200606static DEFINE_PCI_DEVICE_TABLE(snd_hdsp_ids) = {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700607 {
608 .vendor = PCI_VENDOR_ID_XILINX,
Tim Blechmannf9ffc5d2009-02-20 19:38:16 +0100609 .device = PCI_DEVICE_ID_XILINX_HAMMERFALL_DSP,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700610 .subvendor = PCI_ANY_ID,
611 .subdevice = PCI_ANY_ID,
612 }, /* RME Hammerfall-DSP */
613 { 0, },
614};
615
616MODULE_DEVICE_TABLE(pci, snd_hdsp_ids);
617
618/* prototypes */
Takashi Iwai55e957d2005-11-17 14:52:13 +0100619static int snd_hdsp_create_alsa_devices(struct snd_card *card, struct hdsp *hdsp);
620static int snd_hdsp_create_pcm(struct snd_card *card, struct hdsp *hdsp);
621static int snd_hdsp_enable_io (struct hdsp *hdsp);
622static void snd_hdsp_initialize_midi_flush (struct hdsp *hdsp);
623static void snd_hdsp_initialize_channels (struct hdsp *hdsp);
624static int hdsp_fifo_wait(struct hdsp *hdsp, int count, int timeout);
625static int hdsp_autosync_ref(struct hdsp *hdsp);
626static int snd_hdsp_set_defaults(struct hdsp *hdsp);
627static void snd_hdsp_9652_enable_mixer (struct hdsp *hdsp);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700628
Takashi Iwai55e957d2005-11-17 14:52:13 +0100629static int hdsp_playback_to_output_key (struct hdsp *hdsp, int in, int out)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700630{
Remy Brunoa3a68c82007-08-31 12:33:54 +0200631 switch (hdsp->io_type) {
632 case Multiface:
633 case Digiface:
Florian Faber28b26e12010-12-01 12:14:47 +0100634 case RPM:
Linus Torvalds1da177e2005-04-16 15:20:36 -0700635 default:
Andreas Degert192b8e32008-01-16 15:59:48 +0100636 if (hdsp->firmware_rev == 0xa)
637 return (64 * out) + (32 + (in));
638 else
639 return (52 * out) + (26 + (in));
Remy Brunoa3a68c82007-08-31 12:33:54 +0200640 case H9632:
641 return (32 * out) + (16 + (in));
642 case H9652:
Linus Torvalds1da177e2005-04-16 15:20:36 -0700643 return (52 * out) + (26 + (in));
644 }
645}
646
Takashi Iwai55e957d2005-11-17 14:52:13 +0100647static int hdsp_input_to_output_key (struct hdsp *hdsp, int in, int out)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700648{
Remy Brunoa3a68c82007-08-31 12:33:54 +0200649 switch (hdsp->io_type) {
650 case Multiface:
651 case Digiface:
Florian Faber28b26e12010-12-01 12:14:47 +0100652 case RPM:
Linus Torvalds1da177e2005-04-16 15:20:36 -0700653 default:
Andreas Degert192b8e32008-01-16 15:59:48 +0100654 if (hdsp->firmware_rev == 0xa)
655 return (64 * out) + in;
656 else
657 return (52 * out) + in;
Remy Brunoa3a68c82007-08-31 12:33:54 +0200658 case H9632:
659 return (32 * out) + in;
660 case H9652:
Linus Torvalds1da177e2005-04-16 15:20:36 -0700661 return (52 * out) + in;
662 }
663}
664
Takashi Iwai55e957d2005-11-17 14:52:13 +0100665static void hdsp_write(struct hdsp *hdsp, int reg, int val)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700666{
667 writel(val, hdsp->iobase + reg);
668}
669
Takashi Iwai55e957d2005-11-17 14:52:13 +0100670static unsigned int hdsp_read(struct hdsp *hdsp, int reg)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700671{
672 return readl (hdsp->iobase + reg);
673}
674
Takashi Iwai55e957d2005-11-17 14:52:13 +0100675static int hdsp_check_for_iobox (struct hdsp *hdsp)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700676{
Adrian Knoth0c2bc7c2013-01-15 18:52:20 +0100677 int i;
678
Linus Torvalds1da177e2005-04-16 15:20:36 -0700679 if (hdsp->io_type == H9652 || hdsp->io_type == H9632) return 0;
Adrian Knoth0c2bc7c2013-01-15 18:52:20 +0100680 for (i = 0; i < 500; i++) {
681 if (0 == (hdsp_read(hdsp, HDSP_statusRegister) &
682 HDSP_ConfigError)) {
683 if (i) {
684 snd_printd("Hammerfall-DSP: IO box found after %d ms\n",
685 (20 * i));
686 }
687 return 0;
688 }
689 msleep(20);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700690 }
Adrian Knoth0c2bc7c2013-01-15 18:52:20 +0100691 snd_printk(KERN_ERR "Hammerfall-DSP: no IO box connected!\n");
692 hdsp->state &= ~HDSP_FirmwareLoaded;
693 return -EIO;
Tim Blechmanne588ed82009-02-20 19:30:35 +0100694}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700695
Tim Blechmanne588ed82009-02-20 19:30:35 +0100696static int hdsp_wait_for_iobox(struct hdsp *hdsp, unsigned int loops,
697 unsigned int delay)
698{
699 unsigned int i;
700
701 if (hdsp->io_type == H9652 || hdsp->io_type == H9632)
702 return 0;
703
704 for (i = 0; i != loops; ++i) {
705 if (hdsp_read(hdsp, HDSP_statusRegister) & HDSP_ConfigError)
706 msleep(delay);
707 else {
708 snd_printd("Hammerfall-DSP: iobox found after %ums!\n",
709 i * delay);
710 return 0;
711 }
712 }
713
Florian Faber28b26e12010-12-01 12:14:47 +0100714 snd_printk("Hammerfall-DSP: no IO box connected!\n");
Tim Blechmanne588ed82009-02-20 19:30:35 +0100715 hdsp->state &= ~HDSP_FirmwareLoaded;
716 return -EIO;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700717}
718
Takashi Iwai55e957d2005-11-17 14:52:13 +0100719static int snd_hdsp_load_firmware_from_cache(struct hdsp *hdsp) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700720
721 int i;
722 unsigned long flags;
Takashi Iwai90caaef2012-11-22 16:55:11 +0100723 const u32 *cache;
724
725 if (hdsp->fw_uploaded)
726 cache = hdsp->fw_uploaded;
727 else {
728 if (!hdsp->firmware)
729 return -ENODEV;
730 cache = (u32 *)hdsp->firmware->data;
731 if (!cache)
732 return -ENODEV;
733 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700734
735 if ((hdsp_read (hdsp, HDSP_statusRegister) & HDSP_DllError) != 0) {
Tim Blechmannf9ffc5d2009-02-20 19:38:16 +0100736
Linus Torvalds1da177e2005-04-16 15:20:36 -0700737 snd_printk ("Hammerfall-DSP: loading firmware\n");
738
739 hdsp_write (hdsp, HDSP_control2Reg, HDSP_S_PROGRAM);
740 hdsp_write (hdsp, HDSP_fifoData, 0);
Tim Blechmannf9ffc5d2009-02-20 19:38:16 +0100741
Linus Torvalds1da177e2005-04-16 15:20:36 -0700742 if (hdsp_fifo_wait (hdsp, 0, HDSP_LONG_WAIT)) {
743 snd_printk ("Hammerfall-DSP: timeout waiting for download preparation\n");
Adrian Knoth0c2bc7c2013-01-15 18:52:20 +0100744 hdsp_write(hdsp, HDSP_control2Reg, HDSP_S200);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700745 return -EIO;
746 }
Tim Blechmannf9ffc5d2009-02-20 19:38:16 +0100747
Linus Torvalds1da177e2005-04-16 15:20:36 -0700748 hdsp_write (hdsp, HDSP_control2Reg, HDSP_S_LOAD);
Tim Blechmannf9ffc5d2009-02-20 19:38:16 +0100749
Takashi Iwai90caaef2012-11-22 16:55:11 +0100750 for (i = 0; i < HDSP_FIRMWARE_SIZE / 4; ++i) {
751 hdsp_write(hdsp, HDSP_fifoData, cache[i]);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700752 if (hdsp_fifo_wait (hdsp, 127, HDSP_LONG_WAIT)) {
753 snd_printk ("Hammerfall-DSP: timeout during firmware loading\n");
Adrian Knoth0c2bc7c2013-01-15 18:52:20 +0100754 hdsp_write(hdsp, HDSP_control2Reg, HDSP_S200);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700755 return -EIO;
756 }
757 }
758
Adrian Knoth0c2bc7c2013-01-15 18:52:20 +0100759 hdsp_fifo_wait(hdsp, 3, HDSP_LONG_WAIT);
760 hdsp_write(hdsp, HDSP_control2Reg, HDSP_S200);
761
Takashi Iwaib0b981192005-10-20 18:29:58 +0200762 ssleep(3);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700763#ifdef SNDRV_BIG_ENDIAN
764 hdsp->control2_register = HDSP_BIGENDIAN_MODE;
765#else
766 hdsp->control2_register = 0;
767#endif
768 hdsp_write (hdsp, HDSP_control2Reg, hdsp->control2_register);
769 snd_printk ("Hammerfall-DSP: finished firmware loading\n");
Tim Blechmannf9ffc5d2009-02-20 19:38:16 +0100770
Linus Torvalds1da177e2005-04-16 15:20:36 -0700771 }
772 if (hdsp->state & HDSP_InitializationComplete) {
Takashi Iwaib0b981192005-10-20 18:29:58 +0200773 snd_printk(KERN_INFO "Hammerfall-DSP: firmware loaded from cache, restoring defaults\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700774 spin_lock_irqsave(&hdsp->lock, flags);
775 snd_hdsp_set_defaults(hdsp);
Tim Blechmannf9ffc5d2009-02-20 19:38:16 +0100776 spin_unlock_irqrestore(&hdsp->lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700777 }
Tim Blechmannf9ffc5d2009-02-20 19:38:16 +0100778
Linus Torvalds1da177e2005-04-16 15:20:36 -0700779 hdsp->state |= HDSP_FirmwareLoaded;
780
781 return 0;
782}
783
Takashi Iwai55e957d2005-11-17 14:52:13 +0100784static int hdsp_get_iobox_version (struct hdsp *hdsp)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700785{
786 if ((hdsp_read (hdsp, HDSP_statusRegister) & HDSP_DllError) != 0) {
Tim Blechmannf9ffc5d2009-02-20 19:38:16 +0100787
Adrian Knoth0c2bc7c2013-01-15 18:52:20 +0100788 hdsp_write(hdsp, HDSP_control2Reg, HDSP_S_LOAD);
789 hdsp_write(hdsp, HDSP_fifoData, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700790
Adrian Knoth0c2bc7c2013-01-15 18:52:20 +0100791 if (hdsp_fifo_wait(hdsp, 0, HDSP_SHORT_WAIT) < 0) {
792 hdsp_write(hdsp, HDSP_control2Reg, HDSP_S300);
Florian Faber28b26e12010-12-01 12:14:47 +0100793 hdsp_write(hdsp, HDSP_control2Reg, HDSP_S_LOAD);
Tim Blechmannf9ffc5d2009-02-20 19:38:16 +0100794 }
Adrian Knoth0c2bc7c2013-01-15 18:52:20 +0100795
796 hdsp_write(hdsp, HDSP_control2Reg, HDSP_S200 | HDSP_PROGRAM);
797 hdsp_write (hdsp, HDSP_fifoData, 0);
798 if (hdsp_fifo_wait(hdsp, 0, HDSP_SHORT_WAIT) < 0) {
799 hdsp->io_type = Multiface;
800 snd_printk("Hammerfall-DSP: Multiface found\n");
801 return 0;
802 }
803
804 hdsp_write(hdsp, HDSP_control2Reg, HDSP_S_LOAD);
805 hdsp_write(hdsp, HDSP_fifoData, 0);
806 if (hdsp_fifo_wait(hdsp, 0, HDSP_SHORT_WAIT) == 0) {
807 hdsp->io_type = Digiface;
808 snd_printk("Hammerfall-DSP: Digiface found\n");
809 return 0;
810 }
811
812 hdsp_write(hdsp, HDSP_control2Reg, HDSP_S300);
813 hdsp_write(hdsp, HDSP_control2Reg, HDSP_S_LOAD);
814 hdsp_write(hdsp, HDSP_fifoData, 0);
815 if (hdsp_fifo_wait(hdsp, 0, HDSP_SHORT_WAIT) == 0) {
816 hdsp->io_type = Multiface;
817 snd_printk("Hammerfall-DSP: Multiface found\n");
818 return 0;
819 }
820
821 hdsp_write(hdsp, HDSP_control2Reg, HDSP_S300);
822 hdsp_write(hdsp, HDSP_control2Reg, HDSP_S_LOAD);
823 hdsp_write(hdsp, HDSP_fifoData, 0);
824 if (hdsp_fifo_wait(hdsp, 0, HDSP_SHORT_WAIT) < 0) {
825 hdsp->io_type = Multiface;
826 snd_printk("Hammerfall-DSP: Multiface found\n");
827 return 0;
828 }
829
830 hdsp->io_type = RPM;
831 snd_printk("Hammerfall-DSP: RPM found\n");
832 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700833 } else {
834 /* firmware was already loaded, get iobox type */
Florian Faber28b26e12010-12-01 12:14:47 +0100835 if (hdsp_read(hdsp, HDSP_status2Register) & HDSP_version2)
836 hdsp->io_type = RPM;
837 else if (hdsp_read(hdsp, HDSP_status2Register) & HDSP_version1)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700838 hdsp->io_type = Multiface;
Takashi Iwaib0b981192005-10-20 18:29:58 +0200839 else
Linus Torvalds1da177e2005-04-16 15:20:36 -0700840 hdsp->io_type = Digiface;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700841 }
842 return 0;
843}
844
845
Takashi Iwai92eed662008-02-22 18:35:56 +0100846static int hdsp_request_fw_loader(struct hdsp *hdsp);
Takashi Iwai311e70a2006-09-06 12:13:37 +0200847
848static int hdsp_check_for_firmware (struct hdsp *hdsp, int load_on_demand)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700849{
Takashi Iwai311e70a2006-09-06 12:13:37 +0200850 if (hdsp->io_type == H9652 || hdsp->io_type == H9632)
851 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700852 if ((hdsp_read (hdsp, HDSP_statusRegister) & HDSP_DllError) != 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700853 hdsp->state &= ~HDSP_FirmwareLoaded;
Takashi Iwai311e70a2006-09-06 12:13:37 +0200854 if (! load_on_demand)
Takashi Iwaib0b981192005-10-20 18:29:58 +0200855 return -EIO;
Takashi Iwai311e70a2006-09-06 12:13:37 +0200856 snd_printk(KERN_ERR "Hammerfall-DSP: firmware not present.\n");
Takashi Iwaib0b981192005-10-20 18:29:58 +0200857 /* try to load firmware */
Takashi Iwai311e70a2006-09-06 12:13:37 +0200858 if (! (hdsp->state & HDSP_FirmwareCached)) {
Takashi Iwai311e70a2006-09-06 12:13:37 +0200859 if (! hdsp_request_fw_loader(hdsp))
860 return 0;
Takashi Iwai311e70a2006-09-06 12:13:37 +0200861 snd_printk(KERN_ERR
862 "Hammerfall-DSP: No firmware loaded nor "
863 "cached, please upload firmware.\n");
864 return -EIO;
Takashi Iwaib0b981192005-10-20 18:29:58 +0200865 }
Takashi Iwai311e70a2006-09-06 12:13:37 +0200866 if (snd_hdsp_load_firmware_from_cache(hdsp) != 0) {
867 snd_printk(KERN_ERR
868 "Hammerfall-DSP: Firmware loading from "
869 "cache failed, please upload manually.\n");
870 return -EIO;
871 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700872 }
873 return 0;
874}
875
876
Takashi Iwai55e957d2005-11-17 14:52:13 +0100877static int hdsp_fifo_wait(struct hdsp *hdsp, int count, int timeout)
Tim Blechmannf9ffc5d2009-02-20 19:38:16 +0100878{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700879 int i;
880
881 /* the fifoStatus registers reports on how many words
882 are available in the command FIFO.
883 */
Tim Blechmannf9ffc5d2009-02-20 19:38:16 +0100884
Linus Torvalds1da177e2005-04-16 15:20:36 -0700885 for (i = 0; i < timeout; i++) {
886
887 if ((int)(hdsp_read (hdsp, HDSP_fifoStatus) & 0xff) <= count)
888 return 0;
889
890 /* not very friendly, but we only do this during a firmware
891 load and changing the mixer, so we just put up with it.
892 */
893
894 udelay (100);
895 }
896
897 snd_printk ("Hammerfall-DSP: wait for FIFO status <= %d failed after %d iterations\n",
898 count, timeout);
899 return -1;
900}
901
Takashi Iwai55e957d2005-11-17 14:52:13 +0100902static int hdsp_read_gain (struct hdsp *hdsp, unsigned int addr)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700903{
Takashi Iwaib0b981192005-10-20 18:29:58 +0200904 if (addr >= HDSP_MATRIX_MIXER_SIZE)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700905 return 0;
Takashi Iwaib0b981192005-10-20 18:29:58 +0200906
Linus Torvalds1da177e2005-04-16 15:20:36 -0700907 return hdsp->mixer_matrix[addr];
908}
909
Takashi Iwai55e957d2005-11-17 14:52:13 +0100910static int hdsp_write_gain(struct hdsp *hdsp, unsigned int addr, unsigned short data)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700911{
912 unsigned int ad;
913
914 if (addr >= HDSP_MATRIX_MIXER_SIZE)
915 return -1;
Tim Blechmannf9ffc5d2009-02-20 19:38:16 +0100916
Linus Torvalds1da177e2005-04-16 15:20:36 -0700917 if (hdsp->io_type == H9652 || hdsp->io_type == H9632) {
918
919 /* from martin bjornsen:
Tim Blechmannf9ffc5d2009-02-20 19:38:16 +0100920
Linus Torvalds1da177e2005-04-16 15:20:36 -0700921 "You can only write dwords to the
922 mixer memory which contain two
923 mixer values in the low and high
924 word. So if you want to change
925 value 0 you have to read value 1
926 from the cache and write both to
927 the first dword in the mixer
928 memory."
929 */
930
Takashi Iwaib0b981192005-10-20 18:29:58 +0200931 if (hdsp->io_type == H9632 && addr >= 512)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700932 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700933
Takashi Iwaib0b981192005-10-20 18:29:58 +0200934 if (hdsp->io_type == H9652 && addr >= 1352)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700935 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700936
937 hdsp->mixer_matrix[addr] = data;
938
Tim Blechmannf9ffc5d2009-02-20 19:38:16 +0100939
Linus Torvalds1da177e2005-04-16 15:20:36 -0700940 /* `addr' addresses a 16-bit wide address, but
941 the address space accessed via hdsp_write
942 uses byte offsets. put another way, addr
943 varies from 0 to 1351, but to access the
944 corresponding memory location, we need
945 to access 0 to 2703 ...
946 */
947 ad = addr/2;
Tim Blechmannf9ffc5d2009-02-20 19:38:16 +0100948
949 hdsp_write (hdsp, 4096 + (ad*4),
950 (hdsp->mixer_matrix[(addr&0x7fe)+1] << 16) +
Linus Torvalds1da177e2005-04-16 15:20:36 -0700951 hdsp->mixer_matrix[addr&0x7fe]);
Tim Blechmannf9ffc5d2009-02-20 19:38:16 +0100952
Linus Torvalds1da177e2005-04-16 15:20:36 -0700953 return 0;
954
955 } else {
956
957 ad = (addr << 16) + data;
Tim Blechmannf9ffc5d2009-02-20 19:38:16 +0100958
Takashi Iwaib0b981192005-10-20 18:29:58 +0200959 if (hdsp_fifo_wait(hdsp, 127, HDSP_LONG_WAIT))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700960 return -1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700961
962 hdsp_write (hdsp, HDSP_fifoData, ad);
963 hdsp->mixer_matrix[addr] = data;
964
965 }
966
967 return 0;
968}
969
Takashi Iwai55e957d2005-11-17 14:52:13 +0100970static int snd_hdsp_use_is_exclusive(struct hdsp *hdsp)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700971{
972 unsigned long flags;
973 int ret = 1;
974
975 spin_lock_irqsave(&hdsp->lock, flags);
976 if ((hdsp->playback_pid != hdsp->capture_pid) &&
Takashi Iwaib0b981192005-10-20 18:29:58 +0200977 (hdsp->playback_pid >= 0) && (hdsp->capture_pid >= 0))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700978 ret = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700979 spin_unlock_irqrestore(&hdsp->lock, flags);
980 return ret;
981}
982
Takashi Iwai55e957d2005-11-17 14:52:13 +0100983static int hdsp_spdif_sample_rate(struct hdsp *hdsp)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700984{
985 unsigned int status = hdsp_read(hdsp, HDSP_statusRegister);
986 unsigned int rate_bits = (status & HDSP_spdifFrequencyMask);
987
Remy Bruno47ba97f2008-02-22 17:57:02 +0100988 /* For the 9632, the mask is different */
989 if (hdsp->io_type == H9632)
990 rate_bits = (status & HDSP_spdifFrequencyMask_9632);
991
Takashi Iwaib0b981192005-10-20 18:29:58 +0200992 if (status & HDSP_SPDIFErrorFlag)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700993 return 0;
Tim Blechmannf9ffc5d2009-02-20 19:38:16 +0100994
Linus Torvalds1da177e2005-04-16 15:20:36 -0700995 switch (rate_bits) {
996 case HDSP_spdifFrequency32KHz: return 32000;
997 case HDSP_spdifFrequency44_1KHz: return 44100;
998 case HDSP_spdifFrequency48KHz: return 48000;
999 case HDSP_spdifFrequency64KHz: return 64000;
1000 case HDSP_spdifFrequency88_2KHz: return 88200;
1001 case HDSP_spdifFrequency96KHz: return 96000;
Tim Blechmannf9ffc5d2009-02-20 19:38:16 +01001002 case HDSP_spdifFrequency128KHz:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001003 if (hdsp->io_type == H9632) return 128000;
1004 break;
Tim Blechmannf9ffc5d2009-02-20 19:38:16 +01001005 case HDSP_spdifFrequency176_4KHz:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001006 if (hdsp->io_type == H9632) return 176400;
1007 break;
Tim Blechmannf9ffc5d2009-02-20 19:38:16 +01001008 case HDSP_spdifFrequency192KHz:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001009 if (hdsp->io_type == H9632) return 192000;
1010 break;
1011 default:
1012 break;
1013 }
1014 snd_printk ("Hammerfall-DSP: unknown spdif frequency status; bits = 0x%x, status = 0x%x\n", rate_bits, status);
1015 return 0;
1016}
1017
Remy Bruno47ba97f2008-02-22 17:57:02 +01001018static int hdsp_external_sample_rate(struct hdsp *hdsp)
1019{
1020 unsigned int status2 = hdsp_read(hdsp, HDSP_status2Register);
1021 unsigned int rate_bits = status2 & HDSP_systemFrequencyMask;
1022
1023 /* For the 9632 card, there seems to be no bit for indicating external
1024 * sample rate greater than 96kHz. The card reports the corresponding
1025 * single speed. So the best means seems to get spdif rate when
1026 * autosync reference is spdif */
1027 if (hdsp->io_type == H9632 &&
1028 hdsp_autosync_ref(hdsp) == HDSP_AUTOSYNC_FROM_SPDIF)
1029 return hdsp_spdif_sample_rate(hdsp);
1030
1031 switch (rate_bits) {
1032 case HDSP_systemFrequency32: return 32000;
1033 case HDSP_systemFrequency44_1: return 44100;
1034 case HDSP_systemFrequency48: return 48000;
1035 case HDSP_systemFrequency64: return 64000;
1036 case HDSP_systemFrequency88_2: return 88200;
1037 case HDSP_systemFrequency96: return 96000;
1038 default:
1039 return 0;
1040 }
1041}
1042
Takashi Iwai55e957d2005-11-17 14:52:13 +01001043static void hdsp_compute_period_size(struct hdsp *hdsp)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001044{
1045 hdsp->period_bytes = 1 << ((hdsp_decode_latency(hdsp->control_register) + 8));
1046}
1047
Takashi Iwai55e957d2005-11-17 14:52:13 +01001048static snd_pcm_uframes_t hdsp_hw_pointer(struct hdsp *hdsp)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001049{
1050 int position;
1051
1052 position = hdsp_read(hdsp, HDSP_statusRegister);
1053
Takashi Iwaib0b981192005-10-20 18:29:58 +02001054 if (!hdsp->precise_ptr)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001055 return (position & HDSP_BufferID) ? (hdsp->period_bytes / 4) : 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001056
1057 position &= HDSP_BufferPositionMask;
1058 position /= 4;
1059 position &= (hdsp->period_bytes/2) - 1;
1060 return position;
1061}
1062
Takashi Iwai55e957d2005-11-17 14:52:13 +01001063static void hdsp_reset_hw_pointer(struct hdsp *hdsp)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001064{
1065 hdsp_write (hdsp, HDSP_resetPointer, 0);
Remy Brunod7923b22006-10-17 12:41:56 +02001066 if (hdsp->io_type == H9632 && hdsp->firmware_rev >= 152)
1067 /* HDSP_resetPointer = HDSP_freqReg, which is strange and
1068 * requires (?) to write again DDS value after a reset pointer
1069 * (at least, it works like this) */
1070 hdsp_write (hdsp, HDSP_freqReg, hdsp->dds_value);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001071}
1072
Takashi Iwai55e957d2005-11-17 14:52:13 +01001073static void hdsp_start_audio(struct hdsp *s)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001074{
1075 s->control_register |= (HDSP_AudioInterruptEnable | HDSP_Start);
1076 hdsp_write(s, HDSP_controlRegister, s->control_register);
1077}
1078
Takashi Iwai55e957d2005-11-17 14:52:13 +01001079static void hdsp_stop_audio(struct hdsp *s)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001080{
1081 s->control_register &= ~(HDSP_Start | HDSP_AudioInterruptEnable);
1082 hdsp_write(s, HDSP_controlRegister, s->control_register);
1083}
1084
Takashi Iwai55e957d2005-11-17 14:52:13 +01001085static void hdsp_silence_playback(struct hdsp *hdsp)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001086{
1087 memset(hdsp->playback_buffer, 0, HDSP_DMA_AREA_BYTES);
1088}
1089
Takashi Iwai55e957d2005-11-17 14:52:13 +01001090static int hdsp_set_interrupt_interval(struct hdsp *s, unsigned int frames)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001091{
1092 int n;
1093
1094 spin_lock_irq(&s->lock);
1095
1096 frames >>= 7;
1097 n = 0;
1098 while (frames) {
1099 n++;
1100 frames >>= 1;
1101 }
1102
1103 s->control_register &= ~HDSP_LatencyMask;
1104 s->control_register |= hdsp_encode_latency(n);
1105
1106 hdsp_write(s, HDSP_controlRegister, s->control_register);
1107
1108 hdsp_compute_period_size(s);
1109
1110 spin_unlock_irq(&s->lock);
1111
1112 return 0;
1113}
1114
Remy Brunod7923b22006-10-17 12:41:56 +02001115static void hdsp_set_dds_value(struct hdsp *hdsp, int rate)
1116{
1117 u64 n;
Tim Blechmannf9ffc5d2009-02-20 19:38:16 +01001118
Remy Brunod7923b22006-10-17 12:41:56 +02001119 if (rate >= 112000)
1120 rate /= 4;
1121 else if (rate >= 56000)
1122 rate /= 2;
1123
Julian Cablee4b60882007-03-19 11:44:40 +01001124 n = DDS_NUMERATOR;
Takashi Iwai3f7440a2009-06-05 17:40:04 +02001125 n = div_u64(n, rate);
Remy Brunod7923b22006-10-17 12:41:56 +02001126 /* n should be less than 2^32 for being written to FREQ register */
Takashi Iwaida3cec32008-08-08 17:12:14 +02001127 snd_BUG_ON(n >> 32);
Remy Brunod7923b22006-10-17 12:41:56 +02001128 /* HDSP_freqReg and HDSP_resetPointer are the same, so keep the DDS
1129 value to write it after a reset */
1130 hdsp->dds_value = n;
1131 hdsp_write(hdsp, HDSP_freqReg, hdsp->dds_value);
1132}
1133
Takashi Iwai55e957d2005-11-17 14:52:13 +01001134static int hdsp_set_rate(struct hdsp *hdsp, int rate, int called_internally)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001135{
1136 int reject_if_open = 0;
1137 int current_rate;
1138 int rate_bits;
1139
1140 /* ASSUMPTION: hdsp->lock is either held, or
1141 there is no need for it (e.g. during module
1142 initialization).
1143 */
Tim Blechmannf9ffc5d2009-02-20 19:38:16 +01001144
1145 if (!(hdsp->control_register & HDSP_ClockModeMaster)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001146 if (called_internally) {
1147 /* request from ctl or card initialization */
Takashi Iwaib0b981192005-10-20 18:29:58 +02001148 snd_printk(KERN_ERR "Hammerfall-DSP: device is not running as a clock master: cannot set sample rate.\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001149 return -1;
Tim Blechmannf9ffc5d2009-02-20 19:38:16 +01001150 } else {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001151 /* hw_param request while in AutoSync mode */
1152 int external_freq = hdsp_external_sample_rate(hdsp);
1153 int spdif_freq = hdsp_spdif_sample_rate(hdsp);
Tim Blechmannf9ffc5d2009-02-20 19:38:16 +01001154
Takashi Iwaib0b981192005-10-20 18:29:58 +02001155 if ((spdif_freq == external_freq*2) && (hdsp_autosync_ref(hdsp) >= HDSP_AUTOSYNC_FROM_ADAT1))
1156 snd_printk(KERN_INFO "Hammerfall-DSP: Detected ADAT in double speed mode\n");
1157 else if (hdsp->io_type == H9632 && (spdif_freq == external_freq*4) && (hdsp_autosync_ref(hdsp) >= HDSP_AUTOSYNC_FROM_ADAT1))
Tim Blechmannf9ffc5d2009-02-20 19:38:16 +01001158 snd_printk(KERN_INFO "Hammerfall-DSP: Detected ADAT in quad speed mode\n");
Takashi Iwaib0b981192005-10-20 18:29:58 +02001159 else if (rate != external_freq) {
1160 snd_printk(KERN_INFO "Hammerfall-DSP: No AutoSync source for requested rate\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001161 return -1;
Tim Blechmannf9ffc5d2009-02-20 19:38:16 +01001162 }
1163 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001164 }
1165
1166 current_rate = hdsp->system_sample_rate;
1167
1168 /* Changing from a "single speed" to a "double speed" rate is
1169 not allowed if any substreams are open. This is because
Tim Blechmannf9ffc5d2009-02-20 19:38:16 +01001170 such a change causes a shift in the location of
Linus Torvalds1da177e2005-04-16 15:20:36 -07001171 the DMA buffers and a reduction in the number of available
Tim Blechmannf9ffc5d2009-02-20 19:38:16 +01001172 buffers.
Linus Torvalds1da177e2005-04-16 15:20:36 -07001173
1174 Note that a similar but essentially insoluble problem
1175 exists for externally-driven rate changes. All we can do
1176 is to flag rate changes in the read/write routines. */
1177
Takashi Iwaib0b981192005-10-20 18:29:58 +02001178 if (rate > 96000 && hdsp->io_type != H9632)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001179 return -EINVAL;
Tim Blechmannf9ffc5d2009-02-20 19:38:16 +01001180
Linus Torvalds1da177e2005-04-16 15:20:36 -07001181 switch (rate) {
1182 case 32000:
Takashi Iwaib0b981192005-10-20 18:29:58 +02001183 if (current_rate > 48000)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001184 reject_if_open = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001185 rate_bits = HDSP_Frequency32KHz;
1186 break;
1187 case 44100:
Takashi Iwaib0b981192005-10-20 18:29:58 +02001188 if (current_rate > 48000)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001189 reject_if_open = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001190 rate_bits = HDSP_Frequency44_1KHz;
1191 break;
1192 case 48000:
Takashi Iwaib0b981192005-10-20 18:29:58 +02001193 if (current_rate > 48000)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001194 reject_if_open = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001195 rate_bits = HDSP_Frequency48KHz;
1196 break;
1197 case 64000:
Takashi Iwaib0b981192005-10-20 18:29:58 +02001198 if (current_rate <= 48000 || current_rate > 96000)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001199 reject_if_open = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001200 rate_bits = HDSP_Frequency64KHz;
1201 break;
1202 case 88200:
Takashi Iwaib0b981192005-10-20 18:29:58 +02001203 if (current_rate <= 48000 || current_rate > 96000)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001204 reject_if_open = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001205 rate_bits = HDSP_Frequency88_2KHz;
1206 break;
1207 case 96000:
Takashi Iwaib0b981192005-10-20 18:29:58 +02001208 if (current_rate <= 48000 || current_rate > 96000)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001209 reject_if_open = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001210 rate_bits = HDSP_Frequency96KHz;
1211 break;
1212 case 128000:
Takashi Iwaib0b981192005-10-20 18:29:58 +02001213 if (current_rate < 128000)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001214 reject_if_open = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001215 rate_bits = HDSP_Frequency128KHz;
1216 break;
1217 case 176400:
Takashi Iwaib0b981192005-10-20 18:29:58 +02001218 if (current_rate < 128000)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001219 reject_if_open = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001220 rate_bits = HDSP_Frequency176_4KHz;
1221 break;
1222 case 192000:
Takashi Iwaib0b981192005-10-20 18:29:58 +02001223 if (current_rate < 128000)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001224 reject_if_open = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001225 rate_bits = HDSP_Frequency192KHz;
1226 break;
1227 default:
1228 return -EINVAL;
1229 }
1230
1231 if (reject_if_open && (hdsp->capture_pid >= 0 || hdsp->playback_pid >= 0)) {
1232 snd_printk ("Hammerfall-DSP: cannot change speed mode (capture PID = %d, playback PID = %d)\n",
1233 hdsp->capture_pid,
1234 hdsp->playback_pid);
1235 return -EBUSY;
1236 }
1237
1238 hdsp->control_register &= ~HDSP_FrequencyMask;
1239 hdsp->control_register |= rate_bits;
1240 hdsp_write(hdsp, HDSP_controlRegister, hdsp->control_register);
1241
Remy Brunod7923b22006-10-17 12:41:56 +02001242 /* For HDSP9632 rev 152, need to set DDS value in FREQ register */
1243 if (hdsp->io_type == H9632 && hdsp->firmware_rev >= 152)
1244 hdsp_set_dds_value(hdsp, rate);
1245
Linus Torvalds1da177e2005-04-16 15:20:36 -07001246 if (rate >= 128000) {
1247 hdsp->channel_map = channel_map_H9632_qs;
1248 } else if (rate > 48000) {
Takashi Iwaib0b981192005-10-20 18:29:58 +02001249 if (hdsp->io_type == H9632)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001250 hdsp->channel_map = channel_map_H9632_ds;
Takashi Iwaib0b981192005-10-20 18:29:58 +02001251 else
Linus Torvalds1da177e2005-04-16 15:20:36 -07001252 hdsp->channel_map = channel_map_ds;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001253 } else {
1254 switch (hdsp->io_type) {
Florian Faber28b26e12010-12-01 12:14:47 +01001255 case RPM:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001256 case Multiface:
1257 hdsp->channel_map = channel_map_mf_ss;
1258 break;
1259 case Digiface:
1260 case H9652:
1261 hdsp->channel_map = channel_map_df_ss;
1262 break;
1263 case H9632:
1264 hdsp->channel_map = channel_map_H9632_ss;
1265 break;
1266 default:
1267 /* should never happen */
1268 break;
1269 }
1270 }
Tim Blechmannf9ffc5d2009-02-20 19:38:16 +01001271
Linus Torvalds1da177e2005-04-16 15:20:36 -07001272 hdsp->system_sample_rate = rate;
1273
1274 return 0;
1275}
1276
1277/*----------------------------------------------------------------------------
1278 MIDI
1279 ----------------------------------------------------------------------------*/
1280
Takashi Iwai55e957d2005-11-17 14:52:13 +01001281static unsigned char snd_hdsp_midi_read_byte (struct hdsp *hdsp, int id)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001282{
1283 /* the hardware already does the relevant bit-mask with 0xff */
Takashi Iwaib0b981192005-10-20 18:29:58 +02001284 if (id)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001285 return hdsp_read(hdsp, HDSP_midiDataIn1);
Takashi Iwaib0b981192005-10-20 18:29:58 +02001286 else
Linus Torvalds1da177e2005-04-16 15:20:36 -07001287 return hdsp_read(hdsp, HDSP_midiDataIn0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001288}
1289
Takashi Iwai55e957d2005-11-17 14:52:13 +01001290static void snd_hdsp_midi_write_byte (struct hdsp *hdsp, int id, int val)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001291{
1292 /* the hardware already does the relevant bit-mask with 0xff */
Takashi Iwaib0b981192005-10-20 18:29:58 +02001293 if (id)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001294 hdsp_write(hdsp, HDSP_midiDataOut1, val);
Takashi Iwaib0b981192005-10-20 18:29:58 +02001295 else
Linus Torvalds1da177e2005-04-16 15:20:36 -07001296 hdsp_write(hdsp, HDSP_midiDataOut0, val);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001297}
1298
Takashi Iwai55e957d2005-11-17 14:52:13 +01001299static int snd_hdsp_midi_input_available (struct hdsp *hdsp, int id)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001300{
Takashi Iwaib0b981192005-10-20 18:29:58 +02001301 if (id)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001302 return (hdsp_read(hdsp, HDSP_midiStatusIn1) & 0xff);
Takashi Iwaib0b981192005-10-20 18:29:58 +02001303 else
Linus Torvalds1da177e2005-04-16 15:20:36 -07001304 return (hdsp_read(hdsp, HDSP_midiStatusIn0) & 0xff);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001305}
1306
Takashi Iwai55e957d2005-11-17 14:52:13 +01001307static int snd_hdsp_midi_output_possible (struct hdsp *hdsp, int id)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001308{
1309 int fifo_bytes_used;
1310
Takashi Iwaib0b981192005-10-20 18:29:58 +02001311 if (id)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001312 fifo_bytes_used = hdsp_read(hdsp, HDSP_midiStatusOut1) & 0xff;
Takashi Iwaib0b981192005-10-20 18:29:58 +02001313 else
Linus Torvalds1da177e2005-04-16 15:20:36 -07001314 fifo_bytes_used = hdsp_read(hdsp, HDSP_midiStatusOut0) & 0xff;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001315
Takashi Iwaib0b981192005-10-20 18:29:58 +02001316 if (fifo_bytes_used < 128)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001317 return 128 - fifo_bytes_used;
Takashi Iwaib0b981192005-10-20 18:29:58 +02001318 else
Linus Torvalds1da177e2005-04-16 15:20:36 -07001319 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001320}
1321
Takashi Iwai55e957d2005-11-17 14:52:13 +01001322static void snd_hdsp_flush_midi_input (struct hdsp *hdsp, int id)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001323{
Takashi Iwaib0b981192005-10-20 18:29:58 +02001324 while (snd_hdsp_midi_input_available (hdsp, id))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001325 snd_hdsp_midi_read_byte (hdsp, id);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001326}
1327
Takashi Iwai55e957d2005-11-17 14:52:13 +01001328static int snd_hdsp_midi_output_write (struct hdsp_midi *hmidi)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001329{
1330 unsigned long flags;
1331 int n_pending;
1332 int to_write;
1333 int i;
1334 unsigned char buf[128];
1335
1336 /* Output is not interrupt driven */
Tim Blechmannf9ffc5d2009-02-20 19:38:16 +01001337
Linus Torvalds1da177e2005-04-16 15:20:36 -07001338 spin_lock_irqsave (&hmidi->lock, flags);
1339 if (hmidi->output) {
1340 if (!snd_rawmidi_transmit_empty (hmidi->output)) {
1341 if ((n_pending = snd_hdsp_midi_output_possible (hmidi->hdsp, hmidi->id)) > 0) {
1342 if (n_pending > (int)sizeof (buf))
1343 n_pending = sizeof (buf);
Tim Blechmannf9ffc5d2009-02-20 19:38:16 +01001344
Linus Torvalds1da177e2005-04-16 15:20:36 -07001345 if ((to_write = snd_rawmidi_transmit (hmidi->output, buf, n_pending)) > 0) {
Tim Blechmannf9ffc5d2009-02-20 19:38:16 +01001346 for (i = 0; i < to_write; ++i)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001347 snd_hdsp_midi_write_byte (hmidi->hdsp, hmidi->id, buf[i]);
1348 }
1349 }
1350 }
1351 }
1352 spin_unlock_irqrestore (&hmidi->lock, flags);
1353 return 0;
1354}
1355
Takashi Iwai55e957d2005-11-17 14:52:13 +01001356static int snd_hdsp_midi_input_read (struct hdsp_midi *hmidi)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001357{
1358 unsigned char buf[128]; /* this buffer is designed to match the MIDI input FIFO size */
1359 unsigned long flags;
1360 int n_pending;
1361 int i;
1362
1363 spin_lock_irqsave (&hmidi->lock, flags);
1364 if ((n_pending = snd_hdsp_midi_input_available (hmidi->hdsp, hmidi->id)) > 0) {
1365 if (hmidi->input) {
Takashi Iwaib0b981192005-10-20 18:29:58 +02001366 if (n_pending > (int)sizeof (buf))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001367 n_pending = sizeof (buf);
Takashi Iwaib0b981192005-10-20 18:29:58 +02001368 for (i = 0; i < n_pending; ++i)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001369 buf[i] = snd_hdsp_midi_read_byte (hmidi->hdsp, hmidi->id);
Takashi Iwaib0b981192005-10-20 18:29:58 +02001370 if (n_pending)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001371 snd_rawmidi_receive (hmidi->input, buf, n_pending);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001372 } else {
1373 /* flush the MIDI input FIFO */
Takashi Iwaib0b981192005-10-20 18:29:58 +02001374 while (--n_pending)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001375 snd_hdsp_midi_read_byte (hmidi->hdsp, hmidi->id);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001376 }
1377 }
1378 hmidi->pending = 0;
Takashi Iwaib0b981192005-10-20 18:29:58 +02001379 if (hmidi->id)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001380 hmidi->hdsp->control_register |= HDSP_Midi1InterruptEnable;
Takashi Iwaib0b981192005-10-20 18:29:58 +02001381 else
Linus Torvalds1da177e2005-04-16 15:20:36 -07001382 hmidi->hdsp->control_register |= HDSP_Midi0InterruptEnable;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001383 hdsp_write(hmidi->hdsp, HDSP_controlRegister, hmidi->hdsp->control_register);
1384 spin_unlock_irqrestore (&hmidi->lock, flags);
1385 return snd_hdsp_midi_output_write (hmidi);
1386}
1387
Takashi Iwai55e957d2005-11-17 14:52:13 +01001388static void snd_hdsp_midi_input_trigger(struct snd_rawmidi_substream *substream, int up)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001389{
Takashi Iwai55e957d2005-11-17 14:52:13 +01001390 struct hdsp *hdsp;
1391 struct hdsp_midi *hmidi;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001392 unsigned long flags;
1393 u32 ie;
1394
Takashi Iwai55e957d2005-11-17 14:52:13 +01001395 hmidi = (struct hdsp_midi *) substream->rmidi->private_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001396 hdsp = hmidi->hdsp;
1397 ie = hmidi->id ? HDSP_Midi1InterruptEnable : HDSP_Midi0InterruptEnable;
1398 spin_lock_irqsave (&hdsp->lock, flags);
1399 if (up) {
1400 if (!(hdsp->control_register & ie)) {
1401 snd_hdsp_flush_midi_input (hdsp, hmidi->id);
1402 hdsp->control_register |= ie;
1403 }
1404 } else {
1405 hdsp->control_register &= ~ie;
1406 tasklet_kill(&hdsp->midi_tasklet);
1407 }
1408
1409 hdsp_write(hdsp, HDSP_controlRegister, hdsp->control_register);
1410 spin_unlock_irqrestore (&hdsp->lock, flags);
1411}
1412
1413static void snd_hdsp_midi_output_timer(unsigned long data)
1414{
Takashi Iwai55e957d2005-11-17 14:52:13 +01001415 struct hdsp_midi *hmidi = (struct hdsp_midi *) data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001416 unsigned long flags;
Tim Blechmannf9ffc5d2009-02-20 19:38:16 +01001417
Linus Torvalds1da177e2005-04-16 15:20:36 -07001418 snd_hdsp_midi_output_write(hmidi);
1419 spin_lock_irqsave (&hmidi->lock, flags);
1420
1421 /* this does not bump hmidi->istimer, because the
1422 kernel automatically removed the timer when it
1423 expired, and we are now adding it back, thus
Tim Blechmannf9ffc5d2009-02-20 19:38:16 +01001424 leaving istimer wherever it was set before.
Linus Torvalds1da177e2005-04-16 15:20:36 -07001425 */
1426
1427 if (hmidi->istimer) {
1428 hmidi->timer.expires = 1 + jiffies;
1429 add_timer(&hmidi->timer);
1430 }
1431
1432 spin_unlock_irqrestore (&hmidi->lock, flags);
1433}
1434
Takashi Iwai55e957d2005-11-17 14:52:13 +01001435static void snd_hdsp_midi_output_trigger(struct snd_rawmidi_substream *substream, int up)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001436{
Takashi Iwai55e957d2005-11-17 14:52:13 +01001437 struct hdsp_midi *hmidi;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001438 unsigned long flags;
1439
Takashi Iwai55e957d2005-11-17 14:52:13 +01001440 hmidi = (struct hdsp_midi *) substream->rmidi->private_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001441 spin_lock_irqsave (&hmidi->lock, flags);
1442 if (up) {
1443 if (!hmidi->istimer) {
1444 init_timer(&hmidi->timer);
1445 hmidi->timer.function = snd_hdsp_midi_output_timer;
1446 hmidi->timer.data = (unsigned long) hmidi;
1447 hmidi->timer.expires = 1 + jiffies;
1448 add_timer(&hmidi->timer);
1449 hmidi->istimer++;
1450 }
1451 } else {
Takashi Iwaib0b981192005-10-20 18:29:58 +02001452 if (hmidi->istimer && --hmidi->istimer <= 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001453 del_timer (&hmidi->timer);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001454 }
1455 spin_unlock_irqrestore (&hmidi->lock, flags);
1456 if (up)
1457 snd_hdsp_midi_output_write(hmidi);
1458}
1459
Takashi Iwai55e957d2005-11-17 14:52:13 +01001460static int snd_hdsp_midi_input_open(struct snd_rawmidi_substream *substream)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001461{
Takashi Iwai55e957d2005-11-17 14:52:13 +01001462 struct hdsp_midi *hmidi;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001463
Takashi Iwai55e957d2005-11-17 14:52:13 +01001464 hmidi = (struct hdsp_midi *) substream->rmidi->private_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001465 spin_lock_irq (&hmidi->lock);
1466 snd_hdsp_flush_midi_input (hmidi->hdsp, hmidi->id);
1467 hmidi->input = substream;
1468 spin_unlock_irq (&hmidi->lock);
1469
1470 return 0;
1471}
1472
Takashi Iwai55e957d2005-11-17 14:52:13 +01001473static int snd_hdsp_midi_output_open(struct snd_rawmidi_substream *substream)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001474{
Takashi Iwai55e957d2005-11-17 14:52:13 +01001475 struct hdsp_midi *hmidi;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001476
Takashi Iwai55e957d2005-11-17 14:52:13 +01001477 hmidi = (struct hdsp_midi *) substream->rmidi->private_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001478 spin_lock_irq (&hmidi->lock);
1479 hmidi->output = substream;
1480 spin_unlock_irq (&hmidi->lock);
1481
1482 return 0;
1483}
1484
Takashi Iwai55e957d2005-11-17 14:52:13 +01001485static int snd_hdsp_midi_input_close(struct snd_rawmidi_substream *substream)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001486{
Takashi Iwai55e957d2005-11-17 14:52:13 +01001487 struct hdsp_midi *hmidi;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001488
1489 snd_hdsp_midi_input_trigger (substream, 0);
1490
Takashi Iwai55e957d2005-11-17 14:52:13 +01001491 hmidi = (struct hdsp_midi *) substream->rmidi->private_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001492 spin_lock_irq (&hmidi->lock);
1493 hmidi->input = NULL;
1494 spin_unlock_irq (&hmidi->lock);
1495
1496 return 0;
1497}
1498
Takashi Iwai55e957d2005-11-17 14:52:13 +01001499static int snd_hdsp_midi_output_close(struct snd_rawmidi_substream *substream)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001500{
Takashi Iwai55e957d2005-11-17 14:52:13 +01001501 struct hdsp_midi *hmidi;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001502
1503 snd_hdsp_midi_output_trigger (substream, 0);
1504
Takashi Iwai55e957d2005-11-17 14:52:13 +01001505 hmidi = (struct hdsp_midi *) substream->rmidi->private_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001506 spin_lock_irq (&hmidi->lock);
1507 hmidi->output = NULL;
1508 spin_unlock_irq (&hmidi->lock);
1509
1510 return 0;
1511}
1512
Takashi Iwai55e957d2005-11-17 14:52:13 +01001513static struct snd_rawmidi_ops snd_hdsp_midi_output =
Linus Torvalds1da177e2005-04-16 15:20:36 -07001514{
1515 .open = snd_hdsp_midi_output_open,
1516 .close = snd_hdsp_midi_output_close,
1517 .trigger = snd_hdsp_midi_output_trigger,
1518};
1519
Takashi Iwai55e957d2005-11-17 14:52:13 +01001520static struct snd_rawmidi_ops snd_hdsp_midi_input =
Linus Torvalds1da177e2005-04-16 15:20:36 -07001521{
1522 .open = snd_hdsp_midi_input_open,
1523 .close = snd_hdsp_midi_input_close,
1524 .trigger = snd_hdsp_midi_input_trigger,
1525};
1526
Takashi Iwaif40b6892006-07-05 16:51:05 +02001527static int snd_hdsp_create_midi (struct snd_card *card, struct hdsp *hdsp, int id)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001528{
1529 char buf[32];
1530
1531 hdsp->midi[id].id = id;
1532 hdsp->midi[id].rmidi = NULL;
1533 hdsp->midi[id].input = NULL;
1534 hdsp->midi[id].output = NULL;
1535 hdsp->midi[id].hdsp = hdsp;
1536 hdsp->midi[id].istimer = 0;
1537 hdsp->midi[id].pending = 0;
1538 spin_lock_init (&hdsp->midi[id].lock);
1539
1540 sprintf (buf, "%s MIDI %d", card->shortname, id+1);
Takashi Iwaib0b981192005-10-20 18:29:58 +02001541 if (snd_rawmidi_new (card, buf, id, 1, 1, &hdsp->midi[id].rmidi) < 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001542 return -1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001543
Jaroslav Kysela972d4c52008-11-12 16:37:48 +01001544 sprintf(hdsp->midi[id].rmidi->name, "HDSP MIDI %d", id+1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001545 hdsp->midi[id].rmidi->private_data = &hdsp->midi[id];
1546
1547 snd_rawmidi_set_ops (hdsp->midi[id].rmidi, SNDRV_RAWMIDI_STREAM_OUTPUT, &snd_hdsp_midi_output);
1548 snd_rawmidi_set_ops (hdsp->midi[id].rmidi, SNDRV_RAWMIDI_STREAM_INPUT, &snd_hdsp_midi_input);
1549
1550 hdsp->midi[id].rmidi->info_flags |= SNDRV_RAWMIDI_INFO_OUTPUT |
1551 SNDRV_RAWMIDI_INFO_INPUT |
1552 SNDRV_RAWMIDI_INFO_DUPLEX;
1553
1554 return 0;
1555}
1556
1557/*-----------------------------------------------------------------------------
1558 Control Interface
1559 ----------------------------------------------------------------------------*/
1560
Takashi Iwai55e957d2005-11-17 14:52:13 +01001561static u32 snd_hdsp_convert_from_aes(struct snd_aes_iec958 *aes)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001562{
1563 u32 val = 0;
1564 val |= (aes->status[0] & IEC958_AES0_PROFESSIONAL) ? HDSP_SPDIFProfessional : 0;
1565 val |= (aes->status[0] & IEC958_AES0_NONAUDIO) ? HDSP_SPDIFNonAudio : 0;
1566 if (val & HDSP_SPDIFProfessional)
1567 val |= (aes->status[0] & IEC958_AES0_PRO_EMPHASIS_5015) ? HDSP_SPDIFEmphasis : 0;
1568 else
1569 val |= (aes->status[0] & IEC958_AES0_CON_EMPHASIS_5015) ? HDSP_SPDIFEmphasis : 0;
1570 return val;
1571}
1572
Takashi Iwai55e957d2005-11-17 14:52:13 +01001573static void snd_hdsp_convert_to_aes(struct snd_aes_iec958 *aes, u32 val)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001574{
1575 aes->status[0] = ((val & HDSP_SPDIFProfessional) ? IEC958_AES0_PROFESSIONAL : 0) |
1576 ((val & HDSP_SPDIFNonAudio) ? IEC958_AES0_NONAUDIO : 0);
1577 if (val & HDSP_SPDIFProfessional)
1578 aes->status[0] |= (val & HDSP_SPDIFEmphasis) ? IEC958_AES0_PRO_EMPHASIS_5015 : 0;
1579 else
1580 aes->status[0] |= (val & HDSP_SPDIFEmphasis) ? IEC958_AES0_CON_EMPHASIS_5015 : 0;
1581}
1582
Takashi Iwai55e957d2005-11-17 14:52:13 +01001583static int snd_hdsp_control_spdif_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001584{
1585 uinfo->type = SNDRV_CTL_ELEM_TYPE_IEC958;
1586 uinfo->count = 1;
1587 return 0;
1588}
1589
Takashi Iwai55e957d2005-11-17 14:52:13 +01001590static int snd_hdsp_control_spdif_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001591{
Takashi Iwai55e957d2005-11-17 14:52:13 +01001592 struct hdsp *hdsp = snd_kcontrol_chip(kcontrol);
Tim Blechmannf9ffc5d2009-02-20 19:38:16 +01001593
Linus Torvalds1da177e2005-04-16 15:20:36 -07001594 snd_hdsp_convert_to_aes(&ucontrol->value.iec958, hdsp->creg_spdif);
1595 return 0;
1596}
1597
Takashi Iwai55e957d2005-11-17 14:52:13 +01001598static int snd_hdsp_control_spdif_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001599{
Takashi Iwai55e957d2005-11-17 14:52:13 +01001600 struct hdsp *hdsp = snd_kcontrol_chip(kcontrol);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001601 int change;
1602 u32 val;
Tim Blechmannf9ffc5d2009-02-20 19:38:16 +01001603
Linus Torvalds1da177e2005-04-16 15:20:36 -07001604 val = snd_hdsp_convert_from_aes(&ucontrol->value.iec958);
1605 spin_lock_irq(&hdsp->lock);
1606 change = val != hdsp->creg_spdif;
1607 hdsp->creg_spdif = val;
1608 spin_unlock_irq(&hdsp->lock);
1609 return change;
1610}
1611
Takashi Iwai55e957d2005-11-17 14:52:13 +01001612static int snd_hdsp_control_spdif_stream_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001613{
1614 uinfo->type = SNDRV_CTL_ELEM_TYPE_IEC958;
1615 uinfo->count = 1;
1616 return 0;
1617}
1618
Takashi Iwai55e957d2005-11-17 14:52:13 +01001619static int snd_hdsp_control_spdif_stream_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001620{
Takashi Iwai55e957d2005-11-17 14:52:13 +01001621 struct hdsp *hdsp = snd_kcontrol_chip(kcontrol);
Tim Blechmannf9ffc5d2009-02-20 19:38:16 +01001622
Linus Torvalds1da177e2005-04-16 15:20:36 -07001623 snd_hdsp_convert_to_aes(&ucontrol->value.iec958, hdsp->creg_spdif_stream);
1624 return 0;
1625}
1626
Takashi Iwai55e957d2005-11-17 14:52:13 +01001627static int snd_hdsp_control_spdif_stream_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001628{
Takashi Iwai55e957d2005-11-17 14:52:13 +01001629 struct hdsp *hdsp = snd_kcontrol_chip(kcontrol);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001630 int change;
1631 u32 val;
Tim Blechmannf9ffc5d2009-02-20 19:38:16 +01001632
Linus Torvalds1da177e2005-04-16 15:20:36 -07001633 val = snd_hdsp_convert_from_aes(&ucontrol->value.iec958);
1634 spin_lock_irq(&hdsp->lock);
1635 change = val != hdsp->creg_spdif_stream;
1636 hdsp->creg_spdif_stream = val;
1637 hdsp->control_register &= ~(HDSP_SPDIFProfessional | HDSP_SPDIFNonAudio | HDSP_SPDIFEmphasis);
1638 hdsp_write(hdsp, HDSP_controlRegister, hdsp->control_register |= val);
1639 spin_unlock_irq(&hdsp->lock);
1640 return change;
1641}
1642
Takashi Iwai55e957d2005-11-17 14:52:13 +01001643static int snd_hdsp_control_spdif_mask_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001644{
1645 uinfo->type = SNDRV_CTL_ELEM_TYPE_IEC958;
1646 uinfo->count = 1;
1647 return 0;
1648}
1649
Takashi Iwai55e957d2005-11-17 14:52:13 +01001650static int snd_hdsp_control_spdif_mask_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001651{
1652 ucontrol->value.iec958.status[0] = kcontrol->private_value;
1653 return 0;
1654}
1655
1656#define HDSP_SPDIF_IN(xname, xindex) \
Clemens Ladisch67ed4162005-07-29 15:32:58 +02001657{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
Linus Torvalds1da177e2005-04-16 15:20:36 -07001658 .name = xname, \
1659 .index = xindex, \
1660 .info = snd_hdsp_info_spdif_in, \
1661 .get = snd_hdsp_get_spdif_in, \
1662 .put = snd_hdsp_put_spdif_in }
1663
Takashi Iwai55e957d2005-11-17 14:52:13 +01001664static unsigned int hdsp_spdif_in(struct hdsp *hdsp)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001665{
1666 return hdsp_decode_spdif_in(hdsp->control_register & HDSP_SPDIFInputMask);
1667}
1668
Takashi Iwai55e957d2005-11-17 14:52:13 +01001669static int hdsp_set_spdif_input(struct hdsp *hdsp, int in)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001670{
1671 hdsp->control_register &= ~HDSP_SPDIFInputMask;
1672 hdsp->control_register |= hdsp_encode_spdif_in(in);
1673 hdsp_write(hdsp, HDSP_controlRegister, hdsp->control_register);
1674 return 0;
1675}
1676
Takashi Iwai55e957d2005-11-17 14:52:13 +01001677static int snd_hdsp_info_spdif_in(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001678{
1679 static char *texts[4] = {"Optical", "Coaxial", "Internal", "AES"};
Takashi Iwai55e957d2005-11-17 14:52:13 +01001680 struct hdsp *hdsp = snd_kcontrol_chip(kcontrol);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001681
1682 uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
1683 uinfo->count = 1;
1684 uinfo->value.enumerated.items = ((hdsp->io_type == H9632) ? 4 : 3);
1685 if (uinfo->value.enumerated.item > ((hdsp->io_type == H9632) ? 3 : 2))
1686 uinfo->value.enumerated.item = ((hdsp->io_type == H9632) ? 3 : 2);
1687 strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]);
1688 return 0;
1689}
1690
Takashi Iwai55e957d2005-11-17 14:52:13 +01001691static int snd_hdsp_get_spdif_in(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001692{
Takashi Iwai55e957d2005-11-17 14:52:13 +01001693 struct hdsp *hdsp = snd_kcontrol_chip(kcontrol);
Tim Blechmannf9ffc5d2009-02-20 19:38:16 +01001694
Linus Torvalds1da177e2005-04-16 15:20:36 -07001695 ucontrol->value.enumerated.item[0] = hdsp_spdif_in(hdsp);
1696 return 0;
1697}
1698
Takashi Iwai55e957d2005-11-17 14:52:13 +01001699static int snd_hdsp_put_spdif_in(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001700{
Takashi Iwai55e957d2005-11-17 14:52:13 +01001701 struct hdsp *hdsp = snd_kcontrol_chip(kcontrol);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001702 int change;
1703 unsigned int val;
Tim Blechmannf9ffc5d2009-02-20 19:38:16 +01001704
Linus Torvalds1da177e2005-04-16 15:20:36 -07001705 if (!snd_hdsp_use_is_exclusive(hdsp))
1706 return -EBUSY;
1707 val = ucontrol->value.enumerated.item[0] % ((hdsp->io_type == H9632) ? 4 : 3);
1708 spin_lock_irq(&hdsp->lock);
1709 change = val != hdsp_spdif_in(hdsp);
1710 if (change)
1711 hdsp_set_spdif_input(hdsp, val);
1712 spin_unlock_irq(&hdsp->lock);
1713 return change;
1714}
1715
Adrian Knoth66d92442013-01-15 18:52:21 +01001716#define HDSP_TOGGLE_SETTING(xname, xindex) \
1717{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
1718 .name = xname, \
1719 .private_value = xindex, \
1720 .info = snd_hdsp_info_toggle_setting, \
1721 .get = snd_hdsp_get_toggle_setting, \
1722 .put = snd_hdsp_put_toggle_setting \
1723}
1724
1725static int hdsp_toggle_setting(struct hdsp *hdsp, u32 regmask)
1726{
1727 return (hdsp->control_register & regmask) ? 1 : 0;
1728}
1729
1730static int hdsp_set_toggle_setting(struct hdsp *hdsp, u32 regmask, int out)
1731{
1732 if (out)
1733 hdsp->control_register |= regmask;
1734 else
1735 hdsp->control_register &= ~regmask;
1736 hdsp_write(hdsp, HDSP_controlRegister, hdsp->control_register);
1737
1738 return 0;
1739}
1740
1741#define snd_hdsp_info_toggle_setting snd_ctl_boolean_mono_info
1742
1743static int snd_hdsp_get_toggle_setting(struct snd_kcontrol *kcontrol,
1744 struct snd_ctl_elem_value *ucontrol)
1745{
1746 struct hdsp *hdsp = snd_kcontrol_chip(kcontrol);
1747 u32 regmask = kcontrol->private_value;
1748
1749 spin_lock_irq(&hdsp->lock);
1750 ucontrol->value.integer.value[0] = hdsp_toggle_setting(hdsp, regmask);
1751 spin_unlock_irq(&hdsp->lock);
1752 return 0;
1753}
1754
1755static int snd_hdsp_put_toggle_setting(struct snd_kcontrol *kcontrol,
1756 struct snd_ctl_elem_value *ucontrol)
1757{
1758 struct hdsp *hdsp = snd_kcontrol_chip(kcontrol);
1759 u32 regmask = kcontrol->private_value;
1760 int change;
1761 unsigned int val;
1762
1763 if (!snd_hdsp_use_is_exclusive(hdsp))
1764 return -EBUSY;
1765 val = ucontrol->value.integer.value[0] & 1;
1766 spin_lock_irq(&hdsp->lock);
1767 change = (int) val != hdsp_toggle_setting(hdsp, regmask);
1768 if (change)
1769 hdsp_set_toggle_setting(hdsp, regmask, val);
1770 spin_unlock_irq(&hdsp->lock);
1771 return change;
1772}
1773
1774
Linus Torvalds1da177e2005-04-16 15:20:36 -07001775#define HDSP_SPDIF_OUT(xname, xindex) \
Clemens Ladisch67ed4162005-07-29 15:32:58 +02001776{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = xindex, \
Linus Torvalds1da177e2005-04-16 15:20:36 -07001777 .info = snd_hdsp_info_spdif_bits, \
1778 .get = snd_hdsp_get_spdif_out, .put = snd_hdsp_put_spdif_out }
1779
Takashi Iwai55e957d2005-11-17 14:52:13 +01001780static int hdsp_spdif_out(struct hdsp *hdsp)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001781{
1782 return (hdsp->control_register & HDSP_SPDIFOpticalOut) ? 1 : 0;
1783}
1784
Takashi Iwai55e957d2005-11-17 14:52:13 +01001785static int hdsp_set_spdif_output(struct hdsp *hdsp, int out)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001786{
Takashi Iwaib0b981192005-10-20 18:29:58 +02001787 if (out)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001788 hdsp->control_register |= HDSP_SPDIFOpticalOut;
Takashi Iwaib0b981192005-10-20 18:29:58 +02001789 else
Linus Torvalds1da177e2005-04-16 15:20:36 -07001790 hdsp->control_register &= ~HDSP_SPDIFOpticalOut;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001791 hdsp_write(hdsp, HDSP_controlRegister, hdsp->control_register);
1792 return 0;
1793}
1794
Takashi Iwaia5ce8892007-07-23 15:42:26 +02001795#define snd_hdsp_info_spdif_bits snd_ctl_boolean_mono_info
Linus Torvalds1da177e2005-04-16 15:20:36 -07001796
Takashi Iwai55e957d2005-11-17 14:52:13 +01001797static int snd_hdsp_get_spdif_out(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001798{
Takashi Iwai55e957d2005-11-17 14:52:13 +01001799 struct hdsp *hdsp = snd_kcontrol_chip(kcontrol);
Tim Blechmannf9ffc5d2009-02-20 19:38:16 +01001800
Linus Torvalds1da177e2005-04-16 15:20:36 -07001801 ucontrol->value.integer.value[0] = hdsp_spdif_out(hdsp);
1802 return 0;
1803}
1804
Takashi Iwai55e957d2005-11-17 14:52:13 +01001805static int snd_hdsp_put_spdif_out(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001806{
Takashi Iwai55e957d2005-11-17 14:52:13 +01001807 struct hdsp *hdsp = snd_kcontrol_chip(kcontrol);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001808 int change;
1809 unsigned int val;
Tim Blechmannf9ffc5d2009-02-20 19:38:16 +01001810
Linus Torvalds1da177e2005-04-16 15:20:36 -07001811 if (!snd_hdsp_use_is_exclusive(hdsp))
1812 return -EBUSY;
1813 val = ucontrol->value.integer.value[0] & 1;
1814 spin_lock_irq(&hdsp->lock);
1815 change = (int)val != hdsp_spdif_out(hdsp);
1816 hdsp_set_spdif_output(hdsp, val);
1817 spin_unlock_irq(&hdsp->lock);
1818 return change;
1819}
1820
1821#define HDSP_SPDIF_PROFESSIONAL(xname, xindex) \
Clemens Ladisch67ed4162005-07-29 15:32:58 +02001822{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = xindex, \
Linus Torvalds1da177e2005-04-16 15:20:36 -07001823 .info = snd_hdsp_info_spdif_bits, \
1824 .get = snd_hdsp_get_spdif_professional, .put = snd_hdsp_put_spdif_professional }
1825
Takashi Iwai55e957d2005-11-17 14:52:13 +01001826static int hdsp_spdif_professional(struct hdsp *hdsp)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001827{
1828 return (hdsp->control_register & HDSP_SPDIFProfessional) ? 1 : 0;
1829}
1830
Takashi Iwai55e957d2005-11-17 14:52:13 +01001831static int hdsp_set_spdif_professional(struct hdsp *hdsp, int val)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001832{
Takashi Iwaib0b981192005-10-20 18:29:58 +02001833 if (val)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001834 hdsp->control_register |= HDSP_SPDIFProfessional;
Takashi Iwaib0b981192005-10-20 18:29:58 +02001835 else
Linus Torvalds1da177e2005-04-16 15:20:36 -07001836 hdsp->control_register &= ~HDSP_SPDIFProfessional;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001837 hdsp_write(hdsp, HDSP_controlRegister, hdsp->control_register);
1838 return 0;
1839}
1840
Takashi Iwai55e957d2005-11-17 14:52:13 +01001841static int snd_hdsp_get_spdif_professional(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001842{
Takashi Iwai55e957d2005-11-17 14:52:13 +01001843 struct hdsp *hdsp = snd_kcontrol_chip(kcontrol);
Tim Blechmannf9ffc5d2009-02-20 19:38:16 +01001844
Linus Torvalds1da177e2005-04-16 15:20:36 -07001845 ucontrol->value.integer.value[0] = hdsp_spdif_professional(hdsp);
1846 return 0;
1847}
1848
Takashi Iwai55e957d2005-11-17 14:52:13 +01001849static int snd_hdsp_put_spdif_professional(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001850{
Takashi Iwai55e957d2005-11-17 14:52:13 +01001851 struct hdsp *hdsp = snd_kcontrol_chip(kcontrol);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001852 int change;
1853 unsigned int val;
Tim Blechmannf9ffc5d2009-02-20 19:38:16 +01001854
Linus Torvalds1da177e2005-04-16 15:20:36 -07001855 if (!snd_hdsp_use_is_exclusive(hdsp))
1856 return -EBUSY;
1857 val = ucontrol->value.integer.value[0] & 1;
1858 spin_lock_irq(&hdsp->lock);
1859 change = (int)val != hdsp_spdif_professional(hdsp);
1860 hdsp_set_spdif_professional(hdsp, val);
1861 spin_unlock_irq(&hdsp->lock);
1862 return change;
1863}
1864
1865#define HDSP_SPDIF_EMPHASIS(xname, xindex) \
Clemens Ladisch67ed4162005-07-29 15:32:58 +02001866{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = xindex, \
Linus Torvalds1da177e2005-04-16 15:20:36 -07001867 .info = snd_hdsp_info_spdif_bits, \
1868 .get = snd_hdsp_get_spdif_emphasis, .put = snd_hdsp_put_spdif_emphasis }
1869
Takashi Iwai55e957d2005-11-17 14:52:13 +01001870static int hdsp_spdif_emphasis(struct hdsp *hdsp)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001871{
1872 return (hdsp->control_register & HDSP_SPDIFEmphasis) ? 1 : 0;
1873}
1874
Takashi Iwai55e957d2005-11-17 14:52:13 +01001875static int hdsp_set_spdif_emphasis(struct hdsp *hdsp, int val)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001876{
Takashi Iwaib0b981192005-10-20 18:29:58 +02001877 if (val)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001878 hdsp->control_register |= HDSP_SPDIFEmphasis;
Takashi Iwaib0b981192005-10-20 18:29:58 +02001879 else
Linus Torvalds1da177e2005-04-16 15:20:36 -07001880 hdsp->control_register &= ~HDSP_SPDIFEmphasis;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001881 hdsp_write(hdsp, HDSP_controlRegister, hdsp->control_register);
1882 return 0;
1883}
1884
Takashi Iwai55e957d2005-11-17 14:52:13 +01001885static int snd_hdsp_get_spdif_emphasis(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001886{
Takashi Iwai55e957d2005-11-17 14:52:13 +01001887 struct hdsp *hdsp = snd_kcontrol_chip(kcontrol);
Tim Blechmannf9ffc5d2009-02-20 19:38:16 +01001888
Linus Torvalds1da177e2005-04-16 15:20:36 -07001889 ucontrol->value.integer.value[0] = hdsp_spdif_emphasis(hdsp);
1890 return 0;
1891}
1892
Takashi Iwai55e957d2005-11-17 14:52:13 +01001893static int snd_hdsp_put_spdif_emphasis(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001894{
Takashi Iwai55e957d2005-11-17 14:52:13 +01001895 struct hdsp *hdsp = snd_kcontrol_chip(kcontrol);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001896 int change;
1897 unsigned int val;
Tim Blechmannf9ffc5d2009-02-20 19:38:16 +01001898
Linus Torvalds1da177e2005-04-16 15:20:36 -07001899 if (!snd_hdsp_use_is_exclusive(hdsp))
1900 return -EBUSY;
1901 val = ucontrol->value.integer.value[0] & 1;
1902 spin_lock_irq(&hdsp->lock);
1903 change = (int)val != hdsp_spdif_emphasis(hdsp);
1904 hdsp_set_spdif_emphasis(hdsp, val);
1905 spin_unlock_irq(&hdsp->lock);
1906 return change;
1907}
1908
1909#define HDSP_SPDIF_NON_AUDIO(xname, xindex) \
Clemens Ladisch67ed4162005-07-29 15:32:58 +02001910{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = xindex, \
Linus Torvalds1da177e2005-04-16 15:20:36 -07001911 .info = snd_hdsp_info_spdif_bits, \
1912 .get = snd_hdsp_get_spdif_nonaudio, .put = snd_hdsp_put_spdif_nonaudio }
1913
Takashi Iwai55e957d2005-11-17 14:52:13 +01001914static int hdsp_spdif_nonaudio(struct hdsp *hdsp)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001915{
1916 return (hdsp->control_register & HDSP_SPDIFNonAudio) ? 1 : 0;
1917}
1918
Takashi Iwai55e957d2005-11-17 14:52:13 +01001919static int hdsp_set_spdif_nonaudio(struct hdsp *hdsp, int val)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001920{
Takashi Iwaib0b981192005-10-20 18:29:58 +02001921 if (val)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001922 hdsp->control_register |= HDSP_SPDIFNonAudio;
Takashi Iwaib0b981192005-10-20 18:29:58 +02001923 else
Linus Torvalds1da177e2005-04-16 15:20:36 -07001924 hdsp->control_register &= ~HDSP_SPDIFNonAudio;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001925 hdsp_write(hdsp, HDSP_controlRegister, hdsp->control_register);
1926 return 0;
1927}
1928
Takashi Iwai55e957d2005-11-17 14:52:13 +01001929static int snd_hdsp_get_spdif_nonaudio(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001930{
Takashi Iwai55e957d2005-11-17 14:52:13 +01001931 struct hdsp *hdsp = snd_kcontrol_chip(kcontrol);
Tim Blechmannf9ffc5d2009-02-20 19:38:16 +01001932
Linus Torvalds1da177e2005-04-16 15:20:36 -07001933 ucontrol->value.integer.value[0] = hdsp_spdif_nonaudio(hdsp);
1934 return 0;
1935}
1936
Takashi Iwai55e957d2005-11-17 14:52:13 +01001937static int snd_hdsp_put_spdif_nonaudio(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001938{
Takashi Iwai55e957d2005-11-17 14:52:13 +01001939 struct hdsp *hdsp = snd_kcontrol_chip(kcontrol);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001940 int change;
1941 unsigned int val;
Tim Blechmannf9ffc5d2009-02-20 19:38:16 +01001942
Linus Torvalds1da177e2005-04-16 15:20:36 -07001943 if (!snd_hdsp_use_is_exclusive(hdsp))
1944 return -EBUSY;
1945 val = ucontrol->value.integer.value[0] & 1;
1946 spin_lock_irq(&hdsp->lock);
1947 change = (int)val != hdsp_spdif_nonaudio(hdsp);
1948 hdsp_set_spdif_nonaudio(hdsp, val);
1949 spin_unlock_irq(&hdsp->lock);
1950 return change;
1951}
1952
1953#define HDSP_SPDIF_SAMPLE_RATE(xname, xindex) \
Clemens Ladisch67ed4162005-07-29 15:32:58 +02001954{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
Linus Torvalds1da177e2005-04-16 15:20:36 -07001955 .name = xname, \
1956 .index = xindex, \
1957 .access = SNDRV_CTL_ELEM_ACCESS_READ, \
1958 .info = snd_hdsp_info_spdif_sample_rate, \
1959 .get = snd_hdsp_get_spdif_sample_rate \
1960}
1961
Takashi Iwai55e957d2005-11-17 14:52:13 +01001962static int snd_hdsp_info_spdif_sample_rate(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001963{
1964 static char *texts[] = {"32000", "44100", "48000", "64000", "88200", "96000", "None", "128000", "176400", "192000"};
Takashi Iwai55e957d2005-11-17 14:52:13 +01001965 struct hdsp *hdsp = snd_kcontrol_chip(kcontrol);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001966
1967 uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
1968 uinfo->count = 1;
1969 uinfo->value.enumerated.items = (hdsp->io_type == H9632) ? 10 : 7;
1970 if (uinfo->value.enumerated.item >= uinfo->value.enumerated.items)
1971 uinfo->value.enumerated.item = uinfo->value.enumerated.items - 1;
1972 strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]);
1973 return 0;
1974}
1975
Takashi Iwai55e957d2005-11-17 14:52:13 +01001976static int snd_hdsp_get_spdif_sample_rate(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001977{
Takashi Iwai55e957d2005-11-17 14:52:13 +01001978 struct hdsp *hdsp = snd_kcontrol_chip(kcontrol);
Tim Blechmannf9ffc5d2009-02-20 19:38:16 +01001979
Linus Torvalds1da177e2005-04-16 15:20:36 -07001980 switch (hdsp_spdif_sample_rate(hdsp)) {
1981 case 32000:
1982 ucontrol->value.enumerated.item[0] = 0;
1983 break;
1984 case 44100:
1985 ucontrol->value.enumerated.item[0] = 1;
1986 break;
1987 case 48000:
1988 ucontrol->value.enumerated.item[0] = 2;
1989 break;
1990 case 64000:
1991 ucontrol->value.enumerated.item[0] = 3;
1992 break;
1993 case 88200:
1994 ucontrol->value.enumerated.item[0] = 4;
1995 break;
1996 case 96000:
1997 ucontrol->value.enumerated.item[0] = 5;
1998 break;
1999 case 128000:
2000 ucontrol->value.enumerated.item[0] = 7;
2001 break;
2002 case 176400:
2003 ucontrol->value.enumerated.item[0] = 8;
2004 break;
2005 case 192000:
2006 ucontrol->value.enumerated.item[0] = 9;
2007 break;
2008 default:
Tim Blechmannf9ffc5d2009-02-20 19:38:16 +01002009 ucontrol->value.enumerated.item[0] = 6;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002010 }
2011 return 0;
2012}
2013
2014#define HDSP_SYSTEM_SAMPLE_RATE(xname, xindex) \
Clemens Ladisch67ed4162005-07-29 15:32:58 +02002015{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
Linus Torvalds1da177e2005-04-16 15:20:36 -07002016 .name = xname, \
2017 .index = xindex, \
2018 .access = SNDRV_CTL_ELEM_ACCESS_READ, \
2019 .info = snd_hdsp_info_system_sample_rate, \
2020 .get = snd_hdsp_get_system_sample_rate \
2021}
2022
Takashi Iwai55e957d2005-11-17 14:52:13 +01002023static int snd_hdsp_info_system_sample_rate(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002024{
2025 uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
2026 uinfo->count = 1;
2027 return 0;
2028}
2029
Takashi Iwai55e957d2005-11-17 14:52:13 +01002030static int snd_hdsp_get_system_sample_rate(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002031{
Takashi Iwai55e957d2005-11-17 14:52:13 +01002032 struct hdsp *hdsp = snd_kcontrol_chip(kcontrol);
Tim Blechmannf9ffc5d2009-02-20 19:38:16 +01002033
Linus Torvalds1da177e2005-04-16 15:20:36 -07002034 ucontrol->value.enumerated.item[0] = hdsp->system_sample_rate;
2035 return 0;
2036}
2037
2038#define HDSP_AUTOSYNC_SAMPLE_RATE(xname, xindex) \
Clemens Ladisch67ed4162005-07-29 15:32:58 +02002039{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
Linus Torvalds1da177e2005-04-16 15:20:36 -07002040 .name = xname, \
2041 .index = xindex, \
2042 .access = SNDRV_CTL_ELEM_ACCESS_READ, \
2043 .info = snd_hdsp_info_autosync_sample_rate, \
2044 .get = snd_hdsp_get_autosync_sample_rate \
2045}
2046
Takashi Iwai55e957d2005-11-17 14:52:13 +01002047static int snd_hdsp_info_autosync_sample_rate(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002048{
Takashi Iwai55e957d2005-11-17 14:52:13 +01002049 struct hdsp *hdsp = snd_kcontrol_chip(kcontrol);
Tim Blechmannf9ffc5d2009-02-20 19:38:16 +01002050 static char *texts[] = {"32000", "44100", "48000", "64000", "88200", "96000", "None", "128000", "176400", "192000"};
Linus Torvalds1da177e2005-04-16 15:20:36 -07002051 uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
2052 uinfo->count = 1;
2053 uinfo->value.enumerated.items = (hdsp->io_type == H9632) ? 10 : 7 ;
2054 if (uinfo->value.enumerated.item >= uinfo->value.enumerated.items)
2055 uinfo->value.enumerated.item = uinfo->value.enumerated.items - 1;
2056 strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]);
2057 return 0;
2058}
2059
Takashi Iwai55e957d2005-11-17 14:52:13 +01002060static int snd_hdsp_get_autosync_sample_rate(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002061{
Takashi Iwai55e957d2005-11-17 14:52:13 +01002062 struct hdsp *hdsp = snd_kcontrol_chip(kcontrol);
Tim Blechmannf9ffc5d2009-02-20 19:38:16 +01002063
Linus Torvalds1da177e2005-04-16 15:20:36 -07002064 switch (hdsp_external_sample_rate(hdsp)) {
2065 case 32000:
2066 ucontrol->value.enumerated.item[0] = 0;
2067 break;
2068 case 44100:
2069 ucontrol->value.enumerated.item[0] = 1;
2070 break;
2071 case 48000:
2072 ucontrol->value.enumerated.item[0] = 2;
2073 break;
2074 case 64000:
2075 ucontrol->value.enumerated.item[0] = 3;
2076 break;
2077 case 88200:
2078 ucontrol->value.enumerated.item[0] = 4;
2079 break;
2080 case 96000:
2081 ucontrol->value.enumerated.item[0] = 5;
2082 break;
2083 case 128000:
2084 ucontrol->value.enumerated.item[0] = 7;
2085 break;
2086 case 176400:
2087 ucontrol->value.enumerated.item[0] = 8;
2088 break;
2089 case 192000:
2090 ucontrol->value.enumerated.item[0] = 9;
Tim Blechmannf9ffc5d2009-02-20 19:38:16 +01002091 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002092 default:
Tim Blechmannf9ffc5d2009-02-20 19:38:16 +01002093 ucontrol->value.enumerated.item[0] = 6;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002094 }
2095 return 0;
2096}
2097
2098#define HDSP_SYSTEM_CLOCK_MODE(xname, xindex) \
Clemens Ladisch67ed4162005-07-29 15:32:58 +02002099{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
Linus Torvalds1da177e2005-04-16 15:20:36 -07002100 .name = xname, \
2101 .index = xindex, \
2102 .access = SNDRV_CTL_ELEM_ACCESS_READ, \
2103 .info = snd_hdsp_info_system_clock_mode, \
2104 .get = snd_hdsp_get_system_clock_mode \
2105}
2106
Takashi Iwai55e957d2005-11-17 14:52:13 +01002107static int hdsp_system_clock_mode(struct hdsp *hdsp)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002108{
Takashi Iwaib0b981192005-10-20 18:29:58 +02002109 if (hdsp->control_register & HDSP_ClockModeMaster)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002110 return 0;
Takashi Iwaib0b981192005-10-20 18:29:58 +02002111 else if (hdsp_external_sample_rate(hdsp) != hdsp->system_sample_rate)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002112 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002113 return 1;
2114}
2115
Takashi Iwai55e957d2005-11-17 14:52:13 +01002116static int snd_hdsp_info_system_clock_mode(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002117{
2118 static char *texts[] = {"Master", "Slave" };
Tim Blechmannf9ffc5d2009-02-20 19:38:16 +01002119
Linus Torvalds1da177e2005-04-16 15:20:36 -07002120 uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
2121 uinfo->count = 1;
2122 uinfo->value.enumerated.items = 2;
2123 if (uinfo->value.enumerated.item >= uinfo->value.enumerated.items)
2124 uinfo->value.enumerated.item = uinfo->value.enumerated.items - 1;
2125 strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]);
2126 return 0;
2127}
2128
Takashi Iwai55e957d2005-11-17 14:52:13 +01002129static int snd_hdsp_get_system_clock_mode(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002130{
Takashi Iwai55e957d2005-11-17 14:52:13 +01002131 struct hdsp *hdsp = snd_kcontrol_chip(kcontrol);
Tim Blechmannf9ffc5d2009-02-20 19:38:16 +01002132
Linus Torvalds1da177e2005-04-16 15:20:36 -07002133 ucontrol->value.enumerated.item[0] = hdsp_system_clock_mode(hdsp);
2134 return 0;
2135}
2136
2137#define HDSP_CLOCK_SOURCE(xname, xindex) \
Clemens Ladisch67ed4162005-07-29 15:32:58 +02002138{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
Linus Torvalds1da177e2005-04-16 15:20:36 -07002139 .name = xname, \
2140 .index = xindex, \
2141 .info = snd_hdsp_info_clock_source, \
2142 .get = snd_hdsp_get_clock_source, \
2143 .put = snd_hdsp_put_clock_source \
2144}
2145
Takashi Iwai55e957d2005-11-17 14:52:13 +01002146static int hdsp_clock_source(struct hdsp *hdsp)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002147{
2148 if (hdsp->control_register & HDSP_ClockModeMaster) {
2149 switch (hdsp->system_sample_rate) {
2150 case 32000:
2151 return 1;
2152 case 44100:
2153 return 2;
2154 case 48000:
2155 return 3;
2156 case 64000:
2157 return 4;
2158 case 88200:
2159 return 5;
2160 case 96000:
2161 return 6;
2162 case 128000:
2163 return 7;
2164 case 176400:
2165 return 8;
2166 case 192000:
2167 return 9;
2168 default:
Tim Blechmannf9ffc5d2009-02-20 19:38:16 +01002169 return 3;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002170 }
2171 } else {
2172 return 0;
2173 }
2174}
2175
Takashi Iwai55e957d2005-11-17 14:52:13 +01002176static int hdsp_set_clock_source(struct hdsp *hdsp, int mode)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002177{
2178 int rate;
2179 switch (mode) {
2180 case HDSP_CLOCK_SOURCE_AUTOSYNC:
2181 if (hdsp_external_sample_rate(hdsp) != 0) {
2182 if (!hdsp_set_rate(hdsp, hdsp_external_sample_rate(hdsp), 1)) {
Tim Blechmannf9ffc5d2009-02-20 19:38:16 +01002183 hdsp->control_register &= ~HDSP_ClockModeMaster;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002184 hdsp_write(hdsp, HDSP_controlRegister, hdsp->control_register);
2185 return 0;
2186 }
2187 }
2188 return -1;
2189 case HDSP_CLOCK_SOURCE_INTERNAL_32KHZ:
2190 rate = 32000;
2191 break;
2192 case HDSP_CLOCK_SOURCE_INTERNAL_44_1KHZ:
2193 rate = 44100;
Tim Blechmannf9ffc5d2009-02-20 19:38:16 +01002194 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002195 case HDSP_CLOCK_SOURCE_INTERNAL_48KHZ:
2196 rate = 48000;
2197 break;
2198 case HDSP_CLOCK_SOURCE_INTERNAL_64KHZ:
2199 rate = 64000;
2200 break;
2201 case HDSP_CLOCK_SOURCE_INTERNAL_88_2KHZ:
2202 rate = 88200;
2203 break;
2204 case HDSP_CLOCK_SOURCE_INTERNAL_96KHZ:
2205 rate = 96000;
2206 break;
2207 case HDSP_CLOCK_SOURCE_INTERNAL_128KHZ:
2208 rate = 128000;
2209 break;
2210 case HDSP_CLOCK_SOURCE_INTERNAL_176_4KHZ:
2211 rate = 176400;
2212 break;
2213 case HDSP_CLOCK_SOURCE_INTERNAL_192KHZ:
2214 rate = 192000;
2215 break;
2216 default:
2217 rate = 48000;
2218 }
2219 hdsp->control_register |= HDSP_ClockModeMaster;
2220 hdsp_write(hdsp, HDSP_controlRegister, hdsp->control_register);
2221 hdsp_set_rate(hdsp, rate, 1);
2222 return 0;
2223}
2224
Takashi Iwai55e957d2005-11-17 14:52:13 +01002225static int snd_hdsp_info_clock_source(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002226{
2227 static char *texts[] = {"AutoSync", "Internal 32.0 kHz", "Internal 44.1 kHz", "Internal 48.0 kHz", "Internal 64.0 kHz", "Internal 88.2 kHz", "Internal 96.0 kHz", "Internal 128 kHz", "Internal 176.4 kHz", "Internal 192.0 KHz" };
Takashi Iwai55e957d2005-11-17 14:52:13 +01002228 struct hdsp *hdsp = snd_kcontrol_chip(kcontrol);
Tim Blechmannf9ffc5d2009-02-20 19:38:16 +01002229
Linus Torvalds1da177e2005-04-16 15:20:36 -07002230 uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
2231 uinfo->count = 1;
2232 if (hdsp->io_type == H9632)
2233 uinfo->value.enumerated.items = 10;
2234 else
Tim Blechmannf9ffc5d2009-02-20 19:38:16 +01002235 uinfo->value.enumerated.items = 7;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002236 if (uinfo->value.enumerated.item >= uinfo->value.enumerated.items)
2237 uinfo->value.enumerated.item = uinfo->value.enumerated.items - 1;
2238 strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]);
2239 return 0;
2240}
2241
Takashi Iwai55e957d2005-11-17 14:52:13 +01002242static int snd_hdsp_get_clock_source(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002243{
Takashi Iwai55e957d2005-11-17 14:52:13 +01002244 struct hdsp *hdsp = snd_kcontrol_chip(kcontrol);
Tim Blechmannf9ffc5d2009-02-20 19:38:16 +01002245
Linus Torvalds1da177e2005-04-16 15:20:36 -07002246 ucontrol->value.enumerated.item[0] = hdsp_clock_source(hdsp);
2247 return 0;
2248}
2249
Takashi Iwai55e957d2005-11-17 14:52:13 +01002250static int snd_hdsp_put_clock_source(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002251{
Takashi Iwai55e957d2005-11-17 14:52:13 +01002252 struct hdsp *hdsp = snd_kcontrol_chip(kcontrol);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002253 int change;
2254 int val;
Tim Blechmannf9ffc5d2009-02-20 19:38:16 +01002255
Linus Torvalds1da177e2005-04-16 15:20:36 -07002256 if (!snd_hdsp_use_is_exclusive(hdsp))
2257 return -EBUSY;
2258 val = ucontrol->value.enumerated.item[0];
2259 if (val < 0) val = 0;
2260 if (hdsp->io_type == H9632) {
Takashi Iwaib0b981192005-10-20 18:29:58 +02002261 if (val > 9)
2262 val = 9;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002263 } else {
Takashi Iwaib0b981192005-10-20 18:29:58 +02002264 if (val > 6)
2265 val = 6;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002266 }
2267 spin_lock_irq(&hdsp->lock);
Takashi Iwaib0b981192005-10-20 18:29:58 +02002268 if (val != hdsp_clock_source(hdsp))
Linus Torvalds1da177e2005-04-16 15:20:36 -07002269 change = (hdsp_set_clock_source(hdsp, val) == 0) ? 1 : 0;
Takashi Iwaib0b981192005-10-20 18:29:58 +02002270 else
Linus Torvalds1da177e2005-04-16 15:20:36 -07002271 change = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002272 spin_unlock_irq(&hdsp->lock);
2273 return change;
2274}
2275
Takashi Iwaia5ce8892007-07-23 15:42:26 +02002276#define snd_hdsp_info_clock_source_lock snd_ctl_boolean_mono_info
Takashi Iwaie3ea4d82005-07-04 18:12:39 +02002277
Takashi Iwai55e957d2005-11-17 14:52:13 +01002278static int snd_hdsp_get_clock_source_lock(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
Takashi Iwaie3ea4d82005-07-04 18:12:39 +02002279{
Takashi Iwai55e957d2005-11-17 14:52:13 +01002280 struct hdsp *hdsp = snd_kcontrol_chip(kcontrol);
Tim Blechmannf9ffc5d2009-02-20 19:38:16 +01002281
Takashi Iwaie3ea4d82005-07-04 18:12:39 +02002282 ucontrol->value.integer.value[0] = hdsp->clock_source_locked;
2283 return 0;
2284}
2285
Takashi Iwai55e957d2005-11-17 14:52:13 +01002286static int snd_hdsp_put_clock_source_lock(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
Takashi Iwaie3ea4d82005-07-04 18:12:39 +02002287{
Takashi Iwai55e957d2005-11-17 14:52:13 +01002288 struct hdsp *hdsp = snd_kcontrol_chip(kcontrol);
Takashi Iwaie3ea4d82005-07-04 18:12:39 +02002289 int change;
2290
2291 change = (int)ucontrol->value.integer.value[0] != hdsp->clock_source_locked;
2292 if (change)
Takashi Iwai4e98d6a2007-11-15 15:58:13 +01002293 hdsp->clock_source_locked = !!ucontrol->value.integer.value[0];
Takashi Iwaie3ea4d82005-07-04 18:12:39 +02002294 return change;
2295}
2296
Linus Torvalds1da177e2005-04-16 15:20:36 -07002297#define HDSP_DA_GAIN(xname, xindex) \
Clemens Ladisch67ed4162005-07-29 15:32:58 +02002298{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
Linus Torvalds1da177e2005-04-16 15:20:36 -07002299 .name = xname, \
2300 .index = xindex, \
2301 .info = snd_hdsp_info_da_gain, \
2302 .get = snd_hdsp_get_da_gain, \
2303 .put = snd_hdsp_put_da_gain \
2304}
2305
Takashi Iwai55e957d2005-11-17 14:52:13 +01002306static int hdsp_da_gain(struct hdsp *hdsp)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002307{
2308 switch (hdsp->control_register & HDSP_DAGainMask) {
2309 case HDSP_DAGainHighGain:
2310 return 0;
2311 case HDSP_DAGainPlus4dBu:
2312 return 1;
2313 case HDSP_DAGainMinus10dBV:
2314 return 2;
2315 default:
Tim Blechmannf9ffc5d2009-02-20 19:38:16 +01002316 return 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002317 }
2318}
2319
Takashi Iwai55e957d2005-11-17 14:52:13 +01002320static int hdsp_set_da_gain(struct hdsp *hdsp, int mode)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002321{
2322 hdsp->control_register &= ~HDSP_DAGainMask;
2323 switch (mode) {
2324 case 0:
2325 hdsp->control_register |= HDSP_DAGainHighGain;
2326 break;
2327 case 1:
2328 hdsp->control_register |= HDSP_DAGainPlus4dBu;
2329 break;
2330 case 2:
Tim Blechmannf9ffc5d2009-02-20 19:38:16 +01002331 hdsp->control_register |= HDSP_DAGainMinus10dBV;
2332 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002333 default:
2334 return -1;
2335
2336 }
2337 hdsp_write(hdsp, HDSP_controlRegister, hdsp->control_register);
2338 return 0;
2339}
2340
Takashi Iwai55e957d2005-11-17 14:52:13 +01002341static int snd_hdsp_info_da_gain(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002342{
2343 static char *texts[] = {"Hi Gain", "+4 dBu", "-10 dbV"};
Tim Blechmannf9ffc5d2009-02-20 19:38:16 +01002344
Linus Torvalds1da177e2005-04-16 15:20:36 -07002345 uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
2346 uinfo->count = 1;
2347 uinfo->value.enumerated.items = 3;
2348 if (uinfo->value.enumerated.item >= uinfo->value.enumerated.items)
2349 uinfo->value.enumerated.item = uinfo->value.enumerated.items - 1;
2350 strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]);
2351 return 0;
2352}
2353
Takashi Iwai55e957d2005-11-17 14:52:13 +01002354static int snd_hdsp_get_da_gain(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002355{
Takashi Iwai55e957d2005-11-17 14:52:13 +01002356 struct hdsp *hdsp = snd_kcontrol_chip(kcontrol);
Tim Blechmannf9ffc5d2009-02-20 19:38:16 +01002357
Linus Torvalds1da177e2005-04-16 15:20:36 -07002358 ucontrol->value.enumerated.item[0] = hdsp_da_gain(hdsp);
2359 return 0;
2360}
2361
Takashi Iwai55e957d2005-11-17 14:52:13 +01002362static int snd_hdsp_put_da_gain(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002363{
Takashi Iwai55e957d2005-11-17 14:52:13 +01002364 struct hdsp *hdsp = snd_kcontrol_chip(kcontrol);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002365 int change;
2366 int val;
Tim Blechmannf9ffc5d2009-02-20 19:38:16 +01002367
Linus Torvalds1da177e2005-04-16 15:20:36 -07002368 if (!snd_hdsp_use_is_exclusive(hdsp))
2369 return -EBUSY;
2370 val = ucontrol->value.enumerated.item[0];
2371 if (val < 0) val = 0;
2372 if (val > 2) val = 2;
2373 spin_lock_irq(&hdsp->lock);
Takashi Iwaib0b981192005-10-20 18:29:58 +02002374 if (val != hdsp_da_gain(hdsp))
Linus Torvalds1da177e2005-04-16 15:20:36 -07002375 change = (hdsp_set_da_gain(hdsp, val) == 0) ? 1 : 0;
Takashi Iwaib0b981192005-10-20 18:29:58 +02002376 else
Linus Torvalds1da177e2005-04-16 15:20:36 -07002377 change = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002378 spin_unlock_irq(&hdsp->lock);
2379 return change;
2380}
2381
2382#define HDSP_AD_GAIN(xname, xindex) \
Clemens Ladisch67ed4162005-07-29 15:32:58 +02002383{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
Linus Torvalds1da177e2005-04-16 15:20:36 -07002384 .name = xname, \
2385 .index = xindex, \
2386 .info = snd_hdsp_info_ad_gain, \
2387 .get = snd_hdsp_get_ad_gain, \
2388 .put = snd_hdsp_put_ad_gain \
2389}
2390
Takashi Iwai55e957d2005-11-17 14:52:13 +01002391static int hdsp_ad_gain(struct hdsp *hdsp)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002392{
2393 switch (hdsp->control_register & HDSP_ADGainMask) {
2394 case HDSP_ADGainMinus10dBV:
2395 return 0;
2396 case HDSP_ADGainPlus4dBu:
2397 return 1;
2398 case HDSP_ADGainLowGain:
2399 return 2;
2400 default:
Tim Blechmannf9ffc5d2009-02-20 19:38:16 +01002401 return 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002402 }
2403}
2404
Takashi Iwai55e957d2005-11-17 14:52:13 +01002405static int hdsp_set_ad_gain(struct hdsp *hdsp, int mode)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002406{
2407 hdsp->control_register &= ~HDSP_ADGainMask;
2408 switch (mode) {
2409 case 0:
2410 hdsp->control_register |= HDSP_ADGainMinus10dBV;
2411 break;
2412 case 1:
Tim Blechmannf9ffc5d2009-02-20 19:38:16 +01002413 hdsp->control_register |= HDSP_ADGainPlus4dBu;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002414 break;
2415 case 2:
Tim Blechmannf9ffc5d2009-02-20 19:38:16 +01002416 hdsp->control_register |= HDSP_ADGainLowGain;
2417 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002418 default:
2419 return -1;
2420
2421 }
2422 hdsp_write(hdsp, HDSP_controlRegister, hdsp->control_register);
2423 return 0;
2424}
2425
Takashi Iwai55e957d2005-11-17 14:52:13 +01002426static int snd_hdsp_info_ad_gain(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002427{
2428 static char *texts[] = {"-10 dBV", "+4 dBu", "Lo Gain"};
Tim Blechmannf9ffc5d2009-02-20 19:38:16 +01002429
Linus Torvalds1da177e2005-04-16 15:20:36 -07002430 uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
2431 uinfo->count = 1;
2432 uinfo->value.enumerated.items = 3;
2433 if (uinfo->value.enumerated.item >= uinfo->value.enumerated.items)
2434 uinfo->value.enumerated.item = uinfo->value.enumerated.items - 1;
2435 strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]);
2436 return 0;
2437}
2438
Takashi Iwai55e957d2005-11-17 14:52:13 +01002439static int snd_hdsp_get_ad_gain(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002440{
Takashi Iwai55e957d2005-11-17 14:52:13 +01002441 struct hdsp *hdsp = snd_kcontrol_chip(kcontrol);
Tim Blechmannf9ffc5d2009-02-20 19:38:16 +01002442
Linus Torvalds1da177e2005-04-16 15:20:36 -07002443 ucontrol->value.enumerated.item[0] = hdsp_ad_gain(hdsp);
2444 return 0;
2445}
2446
Takashi Iwai55e957d2005-11-17 14:52:13 +01002447static int snd_hdsp_put_ad_gain(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002448{
Takashi Iwai55e957d2005-11-17 14:52:13 +01002449 struct hdsp *hdsp = snd_kcontrol_chip(kcontrol);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002450 int change;
2451 int val;
Tim Blechmannf9ffc5d2009-02-20 19:38:16 +01002452
Linus Torvalds1da177e2005-04-16 15:20:36 -07002453 if (!snd_hdsp_use_is_exclusive(hdsp))
2454 return -EBUSY;
2455 val = ucontrol->value.enumerated.item[0];
2456 if (val < 0) val = 0;
2457 if (val > 2) val = 2;
2458 spin_lock_irq(&hdsp->lock);
Takashi Iwaib0b981192005-10-20 18:29:58 +02002459 if (val != hdsp_ad_gain(hdsp))
Linus Torvalds1da177e2005-04-16 15:20:36 -07002460 change = (hdsp_set_ad_gain(hdsp, val) == 0) ? 1 : 0;
Takashi Iwaib0b981192005-10-20 18:29:58 +02002461 else
Linus Torvalds1da177e2005-04-16 15:20:36 -07002462 change = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002463 spin_unlock_irq(&hdsp->lock);
2464 return change;
2465}
2466
2467#define HDSP_PHONE_GAIN(xname, xindex) \
Clemens Ladisch67ed4162005-07-29 15:32:58 +02002468{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
Linus Torvalds1da177e2005-04-16 15:20:36 -07002469 .name = xname, \
2470 .index = xindex, \
2471 .info = snd_hdsp_info_phone_gain, \
2472 .get = snd_hdsp_get_phone_gain, \
2473 .put = snd_hdsp_put_phone_gain \
2474}
2475
Takashi Iwai55e957d2005-11-17 14:52:13 +01002476static int hdsp_phone_gain(struct hdsp *hdsp)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002477{
2478 switch (hdsp->control_register & HDSP_PhoneGainMask) {
2479 case HDSP_PhoneGain0dB:
2480 return 0;
2481 case HDSP_PhoneGainMinus6dB:
2482 return 1;
2483 case HDSP_PhoneGainMinus12dB:
2484 return 2;
2485 default:
Tim Blechmannf9ffc5d2009-02-20 19:38:16 +01002486 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002487 }
2488}
2489
Takashi Iwai55e957d2005-11-17 14:52:13 +01002490static int hdsp_set_phone_gain(struct hdsp *hdsp, int mode)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002491{
2492 hdsp->control_register &= ~HDSP_PhoneGainMask;
2493 switch (mode) {
2494 case 0:
2495 hdsp->control_register |= HDSP_PhoneGain0dB;
2496 break;
2497 case 1:
Tim Blechmannf9ffc5d2009-02-20 19:38:16 +01002498 hdsp->control_register |= HDSP_PhoneGainMinus6dB;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002499 break;
2500 case 2:
Tim Blechmannf9ffc5d2009-02-20 19:38:16 +01002501 hdsp->control_register |= HDSP_PhoneGainMinus12dB;
2502 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002503 default:
2504 return -1;
2505
2506 }
2507 hdsp_write(hdsp, HDSP_controlRegister, hdsp->control_register);
2508 return 0;
2509}
2510
Takashi Iwai55e957d2005-11-17 14:52:13 +01002511static int snd_hdsp_info_phone_gain(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002512{
2513 static char *texts[] = {"0 dB", "-6 dB", "-12 dB"};
Tim Blechmannf9ffc5d2009-02-20 19:38:16 +01002514
Linus Torvalds1da177e2005-04-16 15:20:36 -07002515 uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
2516 uinfo->count = 1;
2517 uinfo->value.enumerated.items = 3;
2518 if (uinfo->value.enumerated.item >= uinfo->value.enumerated.items)
2519 uinfo->value.enumerated.item = uinfo->value.enumerated.items - 1;
2520 strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]);
2521 return 0;
2522}
2523
Takashi Iwai55e957d2005-11-17 14:52:13 +01002524static int snd_hdsp_get_phone_gain(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002525{
Takashi Iwai55e957d2005-11-17 14:52:13 +01002526 struct hdsp *hdsp = snd_kcontrol_chip(kcontrol);
Tim Blechmannf9ffc5d2009-02-20 19:38:16 +01002527
Linus Torvalds1da177e2005-04-16 15:20:36 -07002528 ucontrol->value.enumerated.item[0] = hdsp_phone_gain(hdsp);
2529 return 0;
2530}
2531
Takashi Iwai55e957d2005-11-17 14:52:13 +01002532static int snd_hdsp_put_phone_gain(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002533{
Takashi Iwai55e957d2005-11-17 14:52:13 +01002534 struct hdsp *hdsp = snd_kcontrol_chip(kcontrol);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002535 int change;
2536 int val;
Tim Blechmannf9ffc5d2009-02-20 19:38:16 +01002537
Linus Torvalds1da177e2005-04-16 15:20:36 -07002538 if (!snd_hdsp_use_is_exclusive(hdsp))
2539 return -EBUSY;
2540 val = ucontrol->value.enumerated.item[0];
2541 if (val < 0) val = 0;
2542 if (val > 2) val = 2;
2543 spin_lock_irq(&hdsp->lock);
Takashi Iwaib0b981192005-10-20 18:29:58 +02002544 if (val != hdsp_phone_gain(hdsp))
Linus Torvalds1da177e2005-04-16 15:20:36 -07002545 change = (hdsp_set_phone_gain(hdsp, val) == 0) ? 1 : 0;
Takashi Iwaib0b981192005-10-20 18:29:58 +02002546 else
Linus Torvalds1da177e2005-04-16 15:20:36 -07002547 change = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002548 spin_unlock_irq(&hdsp->lock);
2549 return change;
2550}
2551
2552#define HDSP_XLR_BREAKOUT_CABLE(xname, xindex) \
Clemens Ladisch67ed4162005-07-29 15:32:58 +02002553{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
Linus Torvalds1da177e2005-04-16 15:20:36 -07002554 .name = xname, \
2555 .index = xindex, \
2556 .info = snd_hdsp_info_xlr_breakout_cable, \
2557 .get = snd_hdsp_get_xlr_breakout_cable, \
2558 .put = snd_hdsp_put_xlr_breakout_cable \
2559}
2560
Takashi Iwai55e957d2005-11-17 14:52:13 +01002561static int hdsp_xlr_breakout_cable(struct hdsp *hdsp)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002562{
Takashi Iwaib0b981192005-10-20 18:29:58 +02002563 if (hdsp->control_register & HDSP_XLRBreakoutCable)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002564 return 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002565 return 0;
2566}
2567
Takashi Iwai55e957d2005-11-17 14:52:13 +01002568static int hdsp_set_xlr_breakout_cable(struct hdsp *hdsp, int mode)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002569{
Takashi Iwaib0b981192005-10-20 18:29:58 +02002570 if (mode)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002571 hdsp->control_register |= HDSP_XLRBreakoutCable;
Takashi Iwaib0b981192005-10-20 18:29:58 +02002572 else
Linus Torvalds1da177e2005-04-16 15:20:36 -07002573 hdsp->control_register &= ~HDSP_XLRBreakoutCable;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002574 hdsp_write(hdsp, HDSP_controlRegister, hdsp->control_register);
2575 return 0;
2576}
2577
Takashi Iwaia5ce8892007-07-23 15:42:26 +02002578#define snd_hdsp_info_xlr_breakout_cable snd_ctl_boolean_mono_info
Linus Torvalds1da177e2005-04-16 15:20:36 -07002579
Takashi Iwai55e957d2005-11-17 14:52:13 +01002580static int snd_hdsp_get_xlr_breakout_cable(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002581{
Takashi Iwai55e957d2005-11-17 14:52:13 +01002582 struct hdsp *hdsp = snd_kcontrol_chip(kcontrol);
Tim Blechmannf9ffc5d2009-02-20 19:38:16 +01002583
Linus Torvalds1da177e2005-04-16 15:20:36 -07002584 ucontrol->value.enumerated.item[0] = hdsp_xlr_breakout_cable(hdsp);
2585 return 0;
2586}
2587
Takashi Iwai55e957d2005-11-17 14:52:13 +01002588static int snd_hdsp_put_xlr_breakout_cable(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002589{
Takashi Iwai55e957d2005-11-17 14:52:13 +01002590 struct hdsp *hdsp = snd_kcontrol_chip(kcontrol);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002591 int change;
2592 int val;
Tim Blechmannf9ffc5d2009-02-20 19:38:16 +01002593
Linus Torvalds1da177e2005-04-16 15:20:36 -07002594 if (!snd_hdsp_use_is_exclusive(hdsp))
2595 return -EBUSY;
2596 val = ucontrol->value.integer.value[0] & 1;
2597 spin_lock_irq(&hdsp->lock);
2598 change = (int)val != hdsp_xlr_breakout_cable(hdsp);
2599 hdsp_set_xlr_breakout_cable(hdsp, val);
2600 spin_unlock_irq(&hdsp->lock);
2601 return change;
2602}
2603
2604/* (De)activates old RME Analog Extension Board
2605 These are connected to the internal ADAT connector
2606 Switching this on desactivates external ADAT
2607*/
2608#define HDSP_AEB(xname, xindex) \
Clemens Ladisch67ed4162005-07-29 15:32:58 +02002609{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
Linus Torvalds1da177e2005-04-16 15:20:36 -07002610 .name = xname, \
2611 .index = xindex, \
2612 .info = snd_hdsp_info_aeb, \
2613 .get = snd_hdsp_get_aeb, \
2614 .put = snd_hdsp_put_aeb \
2615}
2616
Takashi Iwai55e957d2005-11-17 14:52:13 +01002617static int hdsp_aeb(struct hdsp *hdsp)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002618{
Takashi Iwaib0b981192005-10-20 18:29:58 +02002619 if (hdsp->control_register & HDSP_AnalogExtensionBoard)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002620 return 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002621 return 0;
2622}
2623
Takashi Iwai55e957d2005-11-17 14:52:13 +01002624static int hdsp_set_aeb(struct hdsp *hdsp, int mode)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002625{
Takashi Iwaib0b981192005-10-20 18:29:58 +02002626 if (mode)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002627 hdsp->control_register |= HDSP_AnalogExtensionBoard;
Takashi Iwaib0b981192005-10-20 18:29:58 +02002628 else
Linus Torvalds1da177e2005-04-16 15:20:36 -07002629 hdsp->control_register &= ~HDSP_AnalogExtensionBoard;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002630 hdsp_write(hdsp, HDSP_controlRegister, hdsp->control_register);
2631 return 0;
2632}
2633
Takashi Iwaia5ce8892007-07-23 15:42:26 +02002634#define snd_hdsp_info_aeb snd_ctl_boolean_mono_info
Linus Torvalds1da177e2005-04-16 15:20:36 -07002635
Takashi Iwai55e957d2005-11-17 14:52:13 +01002636static int snd_hdsp_get_aeb(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002637{
Takashi Iwai55e957d2005-11-17 14:52:13 +01002638 struct hdsp *hdsp = snd_kcontrol_chip(kcontrol);
Tim Blechmannf9ffc5d2009-02-20 19:38:16 +01002639
Linus Torvalds1da177e2005-04-16 15:20:36 -07002640 ucontrol->value.enumerated.item[0] = hdsp_aeb(hdsp);
2641 return 0;
2642}
2643
Takashi Iwai55e957d2005-11-17 14:52:13 +01002644static int snd_hdsp_put_aeb(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002645{
Takashi Iwai55e957d2005-11-17 14:52:13 +01002646 struct hdsp *hdsp = snd_kcontrol_chip(kcontrol);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002647 int change;
2648 int val;
Tim Blechmannf9ffc5d2009-02-20 19:38:16 +01002649
Linus Torvalds1da177e2005-04-16 15:20:36 -07002650 if (!snd_hdsp_use_is_exclusive(hdsp))
2651 return -EBUSY;
2652 val = ucontrol->value.integer.value[0] & 1;
2653 spin_lock_irq(&hdsp->lock);
2654 change = (int)val != hdsp_aeb(hdsp);
2655 hdsp_set_aeb(hdsp, val);
2656 spin_unlock_irq(&hdsp->lock);
2657 return change;
2658}
2659
2660#define HDSP_PREF_SYNC_REF(xname, xindex) \
Clemens Ladisch67ed4162005-07-29 15:32:58 +02002661{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
Linus Torvalds1da177e2005-04-16 15:20:36 -07002662 .name = xname, \
2663 .index = xindex, \
2664 .info = snd_hdsp_info_pref_sync_ref, \
2665 .get = snd_hdsp_get_pref_sync_ref, \
2666 .put = snd_hdsp_put_pref_sync_ref \
2667}
2668
Takashi Iwai55e957d2005-11-17 14:52:13 +01002669static int hdsp_pref_sync_ref(struct hdsp *hdsp)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002670{
2671 /* Notice that this looks at the requested sync source,
2672 not the one actually in use.
2673 */
2674
2675 switch (hdsp->control_register & HDSP_SyncRefMask) {
2676 case HDSP_SyncRef_ADAT1:
2677 return HDSP_SYNC_FROM_ADAT1;
2678 case HDSP_SyncRef_ADAT2:
2679 return HDSP_SYNC_FROM_ADAT2;
2680 case HDSP_SyncRef_ADAT3:
2681 return HDSP_SYNC_FROM_ADAT3;
2682 case HDSP_SyncRef_SPDIF:
2683 return HDSP_SYNC_FROM_SPDIF;
2684 case HDSP_SyncRef_WORD:
2685 return HDSP_SYNC_FROM_WORD;
2686 case HDSP_SyncRef_ADAT_SYNC:
2687 return HDSP_SYNC_FROM_ADAT_SYNC;
2688 default:
2689 return HDSP_SYNC_FROM_WORD;
2690 }
2691 return 0;
2692}
2693
Takashi Iwai55e957d2005-11-17 14:52:13 +01002694static int hdsp_set_pref_sync_ref(struct hdsp *hdsp, int pref)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002695{
2696 hdsp->control_register &= ~HDSP_SyncRefMask;
2697 switch (pref) {
2698 case HDSP_SYNC_FROM_ADAT1:
2699 hdsp->control_register &= ~HDSP_SyncRefMask; /* clear SyncRef bits */
2700 break;
2701 case HDSP_SYNC_FROM_ADAT2:
2702 hdsp->control_register |= HDSP_SyncRef_ADAT2;
2703 break;
2704 case HDSP_SYNC_FROM_ADAT3:
2705 hdsp->control_register |= HDSP_SyncRef_ADAT3;
2706 break;
2707 case HDSP_SYNC_FROM_SPDIF:
2708 hdsp->control_register |= HDSP_SyncRef_SPDIF;
2709 break;
2710 case HDSP_SYNC_FROM_WORD:
2711 hdsp->control_register |= HDSP_SyncRef_WORD;
2712 break;
2713 case HDSP_SYNC_FROM_ADAT_SYNC:
2714 hdsp->control_register |= HDSP_SyncRef_ADAT_SYNC;
2715 break;
2716 default:
2717 return -1;
2718 }
2719 hdsp_write(hdsp, HDSP_controlRegister, hdsp->control_register);
2720 return 0;
2721}
2722
Takashi Iwai55e957d2005-11-17 14:52:13 +01002723static int snd_hdsp_info_pref_sync_ref(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002724{
2725 static char *texts[] = {"Word", "IEC958", "ADAT1", "ADAT Sync", "ADAT2", "ADAT3" };
Takashi Iwai55e957d2005-11-17 14:52:13 +01002726 struct hdsp *hdsp = snd_kcontrol_chip(kcontrol);
Tim Blechmannf9ffc5d2009-02-20 19:38:16 +01002727
Linus Torvalds1da177e2005-04-16 15:20:36 -07002728 uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
2729 uinfo->count = 1;
2730
2731 switch (hdsp->io_type) {
2732 case Digiface:
2733 case H9652:
2734 uinfo->value.enumerated.items = 6;
2735 break;
2736 case Multiface:
2737 uinfo->value.enumerated.items = 4;
2738 break;
2739 case H9632:
2740 uinfo->value.enumerated.items = 3;
2741 break;
2742 default:
Takashi Iwai9badda02012-01-09 18:22:35 +01002743 return -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002744 }
Tim Blechmannf9ffc5d2009-02-20 19:38:16 +01002745
Linus Torvalds1da177e2005-04-16 15:20:36 -07002746 if (uinfo->value.enumerated.item >= uinfo->value.enumerated.items)
2747 uinfo->value.enumerated.item = uinfo->value.enumerated.items - 1;
2748 strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]);
2749 return 0;
2750}
2751
Takashi Iwai55e957d2005-11-17 14:52:13 +01002752static int snd_hdsp_get_pref_sync_ref(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002753{
Takashi Iwai55e957d2005-11-17 14:52:13 +01002754 struct hdsp *hdsp = snd_kcontrol_chip(kcontrol);
Tim Blechmannf9ffc5d2009-02-20 19:38:16 +01002755
Linus Torvalds1da177e2005-04-16 15:20:36 -07002756 ucontrol->value.enumerated.item[0] = hdsp_pref_sync_ref(hdsp);
2757 return 0;
2758}
2759
Takashi Iwai55e957d2005-11-17 14:52:13 +01002760static int snd_hdsp_put_pref_sync_ref(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002761{
Takashi Iwai55e957d2005-11-17 14:52:13 +01002762 struct hdsp *hdsp = snd_kcontrol_chip(kcontrol);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002763 int change, max;
2764 unsigned int val;
Tim Blechmannf9ffc5d2009-02-20 19:38:16 +01002765
Linus Torvalds1da177e2005-04-16 15:20:36 -07002766 if (!snd_hdsp_use_is_exclusive(hdsp))
2767 return -EBUSY;
2768
2769 switch (hdsp->io_type) {
2770 case Digiface:
2771 case H9652:
2772 max = 6;
2773 break;
2774 case Multiface:
2775 max = 4;
2776 break;
2777 case H9632:
2778 max = 3;
2779 break;
2780 default:
2781 return -EIO;
2782 }
2783
2784 val = ucontrol->value.enumerated.item[0] % max;
2785 spin_lock_irq(&hdsp->lock);
2786 change = (int)val != hdsp_pref_sync_ref(hdsp);
2787 hdsp_set_pref_sync_ref(hdsp, val);
2788 spin_unlock_irq(&hdsp->lock);
2789 return change;
2790}
2791
2792#define HDSP_AUTOSYNC_REF(xname, xindex) \
Clemens Ladisch67ed4162005-07-29 15:32:58 +02002793{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
Linus Torvalds1da177e2005-04-16 15:20:36 -07002794 .name = xname, \
2795 .index = xindex, \
2796 .access = SNDRV_CTL_ELEM_ACCESS_READ, \
2797 .info = snd_hdsp_info_autosync_ref, \
2798 .get = snd_hdsp_get_autosync_ref, \
2799}
2800
Takashi Iwai55e957d2005-11-17 14:52:13 +01002801static int hdsp_autosync_ref(struct hdsp *hdsp)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002802{
2803 /* This looks at the autosync selected sync reference */
2804 unsigned int status2 = hdsp_read(hdsp, HDSP_status2Register);
2805
2806 switch (status2 & HDSP_SelSyncRefMask) {
2807 case HDSP_SelSyncRef_WORD:
2808 return HDSP_AUTOSYNC_FROM_WORD;
2809 case HDSP_SelSyncRef_ADAT_SYNC:
2810 return HDSP_AUTOSYNC_FROM_ADAT_SYNC;
2811 case HDSP_SelSyncRef_SPDIF:
2812 return HDSP_AUTOSYNC_FROM_SPDIF;
2813 case HDSP_SelSyncRefMask:
Tim Blechmannf9ffc5d2009-02-20 19:38:16 +01002814 return HDSP_AUTOSYNC_FROM_NONE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002815 case HDSP_SelSyncRef_ADAT1:
2816 return HDSP_AUTOSYNC_FROM_ADAT1;
2817 case HDSP_SelSyncRef_ADAT2:
2818 return HDSP_AUTOSYNC_FROM_ADAT2;
2819 case HDSP_SelSyncRef_ADAT3:
2820 return HDSP_AUTOSYNC_FROM_ADAT3;
2821 default:
2822 return HDSP_AUTOSYNC_FROM_WORD;
2823 }
2824 return 0;
2825}
2826
Takashi Iwai55e957d2005-11-17 14:52:13 +01002827static int snd_hdsp_info_autosync_ref(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002828{
2829 static char *texts[] = {"Word", "ADAT Sync", "IEC958", "None", "ADAT1", "ADAT2", "ADAT3" };
Tim Blechmannf9ffc5d2009-02-20 19:38:16 +01002830
Linus Torvalds1da177e2005-04-16 15:20:36 -07002831 uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
2832 uinfo->count = 1;
2833 uinfo->value.enumerated.items = 7;
2834 if (uinfo->value.enumerated.item >= uinfo->value.enumerated.items)
2835 uinfo->value.enumerated.item = uinfo->value.enumerated.items - 1;
2836 strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]);
2837 return 0;
2838}
2839
Takashi Iwai55e957d2005-11-17 14:52:13 +01002840static int snd_hdsp_get_autosync_ref(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002841{
Takashi Iwai55e957d2005-11-17 14:52:13 +01002842 struct hdsp *hdsp = snd_kcontrol_chip(kcontrol);
Tim Blechmannf9ffc5d2009-02-20 19:38:16 +01002843
Linus Torvalds1da177e2005-04-16 15:20:36 -07002844 ucontrol->value.enumerated.item[0] = hdsp_autosync_ref(hdsp);
2845 return 0;
2846}
2847
2848#define HDSP_LINE_OUT(xname, xindex) \
Clemens Ladisch67ed4162005-07-29 15:32:58 +02002849{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
Linus Torvalds1da177e2005-04-16 15:20:36 -07002850 .name = xname, \
2851 .index = xindex, \
2852 .info = snd_hdsp_info_line_out, \
2853 .get = snd_hdsp_get_line_out, \
2854 .put = snd_hdsp_put_line_out \
2855}
2856
Takashi Iwai55e957d2005-11-17 14:52:13 +01002857static int hdsp_line_out(struct hdsp *hdsp)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002858{
2859 return (hdsp->control_register & HDSP_LineOut) ? 1 : 0;
2860}
2861
Takashi Iwai55e957d2005-11-17 14:52:13 +01002862static int hdsp_set_line_output(struct hdsp *hdsp, int out)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002863{
Takashi Iwaib0b981192005-10-20 18:29:58 +02002864 if (out)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002865 hdsp->control_register |= HDSP_LineOut;
Takashi Iwaib0b981192005-10-20 18:29:58 +02002866 else
Linus Torvalds1da177e2005-04-16 15:20:36 -07002867 hdsp->control_register &= ~HDSP_LineOut;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002868 hdsp_write(hdsp, HDSP_controlRegister, hdsp->control_register);
2869 return 0;
2870}
2871
Takashi Iwaia5ce8892007-07-23 15:42:26 +02002872#define snd_hdsp_info_line_out snd_ctl_boolean_mono_info
Linus Torvalds1da177e2005-04-16 15:20:36 -07002873
Takashi Iwai55e957d2005-11-17 14:52:13 +01002874static int snd_hdsp_get_line_out(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002875{
Takashi Iwai55e957d2005-11-17 14:52:13 +01002876 struct hdsp *hdsp = snd_kcontrol_chip(kcontrol);
Tim Blechmannf9ffc5d2009-02-20 19:38:16 +01002877
Linus Torvalds1da177e2005-04-16 15:20:36 -07002878 spin_lock_irq(&hdsp->lock);
2879 ucontrol->value.integer.value[0] = hdsp_line_out(hdsp);
2880 spin_unlock_irq(&hdsp->lock);
2881 return 0;
2882}
2883
Takashi Iwai55e957d2005-11-17 14:52:13 +01002884static int snd_hdsp_put_line_out(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002885{
Takashi Iwai55e957d2005-11-17 14:52:13 +01002886 struct hdsp *hdsp = snd_kcontrol_chip(kcontrol);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002887 int change;
2888 unsigned int val;
Tim Blechmannf9ffc5d2009-02-20 19:38:16 +01002889
Linus Torvalds1da177e2005-04-16 15:20:36 -07002890 if (!snd_hdsp_use_is_exclusive(hdsp))
2891 return -EBUSY;
2892 val = ucontrol->value.integer.value[0] & 1;
2893 spin_lock_irq(&hdsp->lock);
2894 change = (int)val != hdsp_line_out(hdsp);
2895 hdsp_set_line_output(hdsp, val);
2896 spin_unlock_irq(&hdsp->lock);
2897 return change;
2898}
2899
2900#define HDSP_PRECISE_POINTER(xname, xindex) \
Clemens Ladisch67ed4162005-07-29 15:32:58 +02002901{ .iface = SNDRV_CTL_ELEM_IFACE_CARD, \
Linus Torvalds1da177e2005-04-16 15:20:36 -07002902 .name = xname, \
2903 .index = xindex, \
2904 .info = snd_hdsp_info_precise_pointer, \
2905 .get = snd_hdsp_get_precise_pointer, \
2906 .put = snd_hdsp_put_precise_pointer \
2907}
2908
Takashi Iwai55e957d2005-11-17 14:52:13 +01002909static int hdsp_set_precise_pointer(struct hdsp *hdsp, int precise)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002910{
Takashi Iwaib0b981192005-10-20 18:29:58 +02002911 if (precise)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002912 hdsp->precise_ptr = 1;
Takashi Iwaib0b981192005-10-20 18:29:58 +02002913 else
Linus Torvalds1da177e2005-04-16 15:20:36 -07002914 hdsp->precise_ptr = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002915 return 0;
2916}
2917
Takashi Iwaia5ce8892007-07-23 15:42:26 +02002918#define snd_hdsp_info_precise_pointer snd_ctl_boolean_mono_info
Linus Torvalds1da177e2005-04-16 15:20:36 -07002919
Takashi Iwai55e957d2005-11-17 14:52:13 +01002920static int snd_hdsp_get_precise_pointer(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002921{
Takashi Iwai55e957d2005-11-17 14:52:13 +01002922 struct hdsp *hdsp = snd_kcontrol_chip(kcontrol);
Tim Blechmannf9ffc5d2009-02-20 19:38:16 +01002923
Linus Torvalds1da177e2005-04-16 15:20:36 -07002924 spin_lock_irq(&hdsp->lock);
2925 ucontrol->value.integer.value[0] = hdsp->precise_ptr;
2926 spin_unlock_irq(&hdsp->lock);
2927 return 0;
2928}
2929
Takashi Iwai55e957d2005-11-17 14:52:13 +01002930static int snd_hdsp_put_precise_pointer(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002931{
Takashi Iwai55e957d2005-11-17 14:52:13 +01002932 struct hdsp *hdsp = snd_kcontrol_chip(kcontrol);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002933 int change;
2934 unsigned int val;
Tim Blechmannf9ffc5d2009-02-20 19:38:16 +01002935
Linus Torvalds1da177e2005-04-16 15:20:36 -07002936 if (!snd_hdsp_use_is_exclusive(hdsp))
2937 return -EBUSY;
2938 val = ucontrol->value.integer.value[0] & 1;
2939 spin_lock_irq(&hdsp->lock);
2940 change = (int)val != hdsp->precise_ptr;
2941 hdsp_set_precise_pointer(hdsp, val);
2942 spin_unlock_irq(&hdsp->lock);
2943 return change;
2944}
2945
2946#define HDSP_USE_MIDI_TASKLET(xname, xindex) \
Clemens Ladisch67ed4162005-07-29 15:32:58 +02002947{ .iface = SNDRV_CTL_ELEM_IFACE_CARD, \
Linus Torvalds1da177e2005-04-16 15:20:36 -07002948 .name = xname, \
2949 .index = xindex, \
2950 .info = snd_hdsp_info_use_midi_tasklet, \
2951 .get = snd_hdsp_get_use_midi_tasklet, \
2952 .put = snd_hdsp_put_use_midi_tasklet \
2953}
2954
Takashi Iwai55e957d2005-11-17 14:52:13 +01002955static int hdsp_set_use_midi_tasklet(struct hdsp *hdsp, int use_tasklet)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002956{
Takashi Iwaib0b981192005-10-20 18:29:58 +02002957 if (use_tasklet)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002958 hdsp->use_midi_tasklet = 1;
Takashi Iwaib0b981192005-10-20 18:29:58 +02002959 else
Linus Torvalds1da177e2005-04-16 15:20:36 -07002960 hdsp->use_midi_tasklet = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002961 return 0;
2962}
2963
Takashi Iwaia5ce8892007-07-23 15:42:26 +02002964#define snd_hdsp_info_use_midi_tasklet snd_ctl_boolean_mono_info
Linus Torvalds1da177e2005-04-16 15:20:36 -07002965
Takashi Iwai55e957d2005-11-17 14:52:13 +01002966static int snd_hdsp_get_use_midi_tasklet(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002967{
Takashi Iwai55e957d2005-11-17 14:52:13 +01002968 struct hdsp *hdsp = snd_kcontrol_chip(kcontrol);
Tim Blechmannf9ffc5d2009-02-20 19:38:16 +01002969
Linus Torvalds1da177e2005-04-16 15:20:36 -07002970 spin_lock_irq(&hdsp->lock);
2971 ucontrol->value.integer.value[0] = hdsp->use_midi_tasklet;
2972 spin_unlock_irq(&hdsp->lock);
2973 return 0;
2974}
2975
Takashi Iwai55e957d2005-11-17 14:52:13 +01002976static int snd_hdsp_put_use_midi_tasklet(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002977{
Takashi Iwai55e957d2005-11-17 14:52:13 +01002978 struct hdsp *hdsp = snd_kcontrol_chip(kcontrol);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002979 int change;
2980 unsigned int val;
Tim Blechmannf9ffc5d2009-02-20 19:38:16 +01002981
Linus Torvalds1da177e2005-04-16 15:20:36 -07002982 if (!snd_hdsp_use_is_exclusive(hdsp))
2983 return -EBUSY;
2984 val = ucontrol->value.integer.value[0] & 1;
2985 spin_lock_irq(&hdsp->lock);
2986 change = (int)val != hdsp->use_midi_tasklet;
2987 hdsp_set_use_midi_tasklet(hdsp, val);
2988 spin_unlock_irq(&hdsp->lock);
2989 return change;
2990}
2991
2992#define HDSP_MIXER(xname, xindex) \
2993{ .iface = SNDRV_CTL_ELEM_IFACE_HWDEP, \
2994 .name = xname, \
2995 .index = xindex, \
Clemens Ladisch67ed4162005-07-29 15:32:58 +02002996 .device = 0, \
Linus Torvalds1da177e2005-04-16 15:20:36 -07002997 .access = SNDRV_CTL_ELEM_ACCESS_READWRITE | \
2998 SNDRV_CTL_ELEM_ACCESS_VOLATILE, \
2999 .info = snd_hdsp_info_mixer, \
3000 .get = snd_hdsp_get_mixer, \
3001 .put = snd_hdsp_put_mixer \
3002}
3003
Takashi Iwai55e957d2005-11-17 14:52:13 +01003004static int snd_hdsp_info_mixer(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003005{
3006 uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
3007 uinfo->count = 3;
3008 uinfo->value.integer.min = 0;
3009 uinfo->value.integer.max = 65536;
3010 uinfo->value.integer.step = 1;
3011 return 0;
3012}
3013
Takashi Iwai55e957d2005-11-17 14:52:13 +01003014static int snd_hdsp_get_mixer(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003015{
Takashi Iwai55e957d2005-11-17 14:52:13 +01003016 struct hdsp *hdsp = snd_kcontrol_chip(kcontrol);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003017 int source;
3018 int destination;
3019 int addr;
3020
3021 source = ucontrol->value.integer.value[0];
3022 destination = ucontrol->value.integer.value[1];
Tim Blechmannf9ffc5d2009-02-20 19:38:16 +01003023
Takashi Iwaib0b981192005-10-20 18:29:58 +02003024 if (source >= hdsp->max_channels)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003025 addr = hdsp_playback_to_output_key(hdsp,source-hdsp->max_channels,destination);
Takashi Iwaib0b981192005-10-20 18:29:58 +02003026 else
Linus Torvalds1da177e2005-04-16 15:20:36 -07003027 addr = hdsp_input_to_output_key(hdsp,source, destination);
Tim Blechmannf9ffc5d2009-02-20 19:38:16 +01003028
Linus Torvalds1da177e2005-04-16 15:20:36 -07003029 spin_lock_irq(&hdsp->lock);
3030 ucontrol->value.integer.value[2] = hdsp_read_gain (hdsp, addr);
3031 spin_unlock_irq(&hdsp->lock);
3032 return 0;
3033}
3034
Takashi Iwai55e957d2005-11-17 14:52:13 +01003035static int snd_hdsp_put_mixer(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003036{
Takashi Iwai55e957d2005-11-17 14:52:13 +01003037 struct hdsp *hdsp = snd_kcontrol_chip(kcontrol);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003038 int change;
3039 int source;
3040 int destination;
3041 int gain;
3042 int addr;
3043
3044 if (!snd_hdsp_use_is_exclusive(hdsp))
3045 return -EBUSY;
3046
3047 source = ucontrol->value.integer.value[0];
3048 destination = ucontrol->value.integer.value[1];
3049
Takashi Iwaib0b981192005-10-20 18:29:58 +02003050 if (source >= hdsp->max_channels)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003051 addr = hdsp_playback_to_output_key(hdsp,source-hdsp->max_channels, destination);
Takashi Iwaib0b981192005-10-20 18:29:58 +02003052 else
Linus Torvalds1da177e2005-04-16 15:20:36 -07003053 addr = hdsp_input_to_output_key(hdsp,source, destination);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003054
3055 gain = ucontrol->value.integer.value[2];
3056
3057 spin_lock_irq(&hdsp->lock);
3058 change = gain != hdsp_read_gain(hdsp, addr);
3059 if (change)
3060 hdsp_write_gain(hdsp, addr, gain);
3061 spin_unlock_irq(&hdsp->lock);
3062 return change;
3063}
3064
3065#define HDSP_WC_SYNC_CHECK(xname, xindex) \
Clemens Ladisch67ed4162005-07-29 15:32:58 +02003066{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
Linus Torvalds1da177e2005-04-16 15:20:36 -07003067 .name = xname, \
3068 .index = xindex, \
3069 .access = SNDRV_CTL_ELEM_ACCESS_READ | SNDRV_CTL_ELEM_ACCESS_VOLATILE, \
3070 .info = snd_hdsp_info_sync_check, \
3071 .get = snd_hdsp_get_wc_sync_check \
3072}
3073
Takashi Iwai55e957d2005-11-17 14:52:13 +01003074static int snd_hdsp_info_sync_check(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003075{
Tim Blechmannf9ffc5d2009-02-20 19:38:16 +01003076 static char *texts[] = {"No Lock", "Lock", "Sync" };
Linus Torvalds1da177e2005-04-16 15:20:36 -07003077 uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
3078 uinfo->count = 1;
3079 uinfo->value.enumerated.items = 3;
3080 if (uinfo->value.enumerated.item >= uinfo->value.enumerated.items)
3081 uinfo->value.enumerated.item = uinfo->value.enumerated.items - 1;
3082 strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]);
3083 return 0;
3084}
3085
Takashi Iwai55e957d2005-11-17 14:52:13 +01003086static int hdsp_wc_sync_check(struct hdsp *hdsp)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003087{
3088 int status2 = hdsp_read(hdsp, HDSP_status2Register);
3089 if (status2 & HDSP_wc_lock) {
Takashi Iwaib0b981192005-10-20 18:29:58 +02003090 if (status2 & HDSP_wc_sync)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003091 return 2;
Takashi Iwaib0b981192005-10-20 18:29:58 +02003092 else
Linus Torvalds1da177e2005-04-16 15:20:36 -07003093 return 1;
Takashi Iwaib0b981192005-10-20 18:29:58 +02003094 } else
Linus Torvalds1da177e2005-04-16 15:20:36 -07003095 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003096 return 0;
3097}
3098
Takashi Iwai55e957d2005-11-17 14:52:13 +01003099static int snd_hdsp_get_wc_sync_check(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003100{
Takashi Iwai55e957d2005-11-17 14:52:13 +01003101 struct hdsp *hdsp = snd_kcontrol_chip(kcontrol);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003102
3103 ucontrol->value.enumerated.item[0] = hdsp_wc_sync_check(hdsp);
3104 return 0;
3105}
3106
3107#define HDSP_SPDIF_SYNC_CHECK(xname, xindex) \
Clemens Ladisch67ed4162005-07-29 15:32:58 +02003108{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
Linus Torvalds1da177e2005-04-16 15:20:36 -07003109 .name = xname, \
3110 .index = xindex, \
3111 .access = SNDRV_CTL_ELEM_ACCESS_READ | SNDRV_CTL_ELEM_ACCESS_VOLATILE, \
3112 .info = snd_hdsp_info_sync_check, \
3113 .get = snd_hdsp_get_spdif_sync_check \
3114}
3115
Takashi Iwai55e957d2005-11-17 14:52:13 +01003116static int hdsp_spdif_sync_check(struct hdsp *hdsp)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003117{
3118 int status = hdsp_read(hdsp, HDSP_statusRegister);
Takashi Iwaib0b981192005-10-20 18:29:58 +02003119 if (status & HDSP_SPDIFErrorFlag)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003120 return 0;
Tim Blechmannf9ffc5d2009-02-20 19:38:16 +01003121 else {
Takashi Iwaib0b981192005-10-20 18:29:58 +02003122 if (status & HDSP_SPDIFSync)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003123 return 2;
Takashi Iwaib0b981192005-10-20 18:29:58 +02003124 else
Linus Torvalds1da177e2005-04-16 15:20:36 -07003125 return 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003126 }
3127 return 0;
3128}
3129
Takashi Iwai55e957d2005-11-17 14:52:13 +01003130static int snd_hdsp_get_spdif_sync_check(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003131{
Takashi Iwai55e957d2005-11-17 14:52:13 +01003132 struct hdsp *hdsp = snd_kcontrol_chip(kcontrol);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003133
3134 ucontrol->value.enumerated.item[0] = hdsp_spdif_sync_check(hdsp);
3135 return 0;
3136}
3137
3138#define HDSP_ADATSYNC_SYNC_CHECK(xname, xindex) \
Clemens Ladisch67ed4162005-07-29 15:32:58 +02003139{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
Linus Torvalds1da177e2005-04-16 15:20:36 -07003140 .name = xname, \
3141 .index = xindex, \
3142 .access = SNDRV_CTL_ELEM_ACCESS_READ | SNDRV_CTL_ELEM_ACCESS_VOLATILE, \
3143 .info = snd_hdsp_info_sync_check, \
3144 .get = snd_hdsp_get_adatsync_sync_check \
3145}
3146
Takashi Iwai55e957d2005-11-17 14:52:13 +01003147static int hdsp_adatsync_sync_check(struct hdsp *hdsp)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003148{
3149 int status = hdsp_read(hdsp, HDSP_statusRegister);
3150 if (status & HDSP_TimecodeLock) {
Takashi Iwaib0b981192005-10-20 18:29:58 +02003151 if (status & HDSP_TimecodeSync)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003152 return 2;
Takashi Iwaib0b981192005-10-20 18:29:58 +02003153 else
Linus Torvalds1da177e2005-04-16 15:20:36 -07003154 return 1;
Takashi Iwaib0b981192005-10-20 18:29:58 +02003155 } else
Linus Torvalds1da177e2005-04-16 15:20:36 -07003156 return 0;
Tim Blechmannf9ffc5d2009-02-20 19:38:16 +01003157}
Linus Torvalds1da177e2005-04-16 15:20:36 -07003158
Takashi Iwai55e957d2005-11-17 14:52:13 +01003159static int snd_hdsp_get_adatsync_sync_check(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003160{
Takashi Iwai55e957d2005-11-17 14:52:13 +01003161 struct hdsp *hdsp = snd_kcontrol_chip(kcontrol);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003162
3163 ucontrol->value.enumerated.item[0] = hdsp_adatsync_sync_check(hdsp);
3164 return 0;
3165}
3166
3167#define HDSP_ADAT_SYNC_CHECK \
Clemens Ladisch67ed4162005-07-29 15:32:58 +02003168{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
Linus Torvalds1da177e2005-04-16 15:20:36 -07003169 .access = SNDRV_CTL_ELEM_ACCESS_READ | SNDRV_CTL_ELEM_ACCESS_VOLATILE, \
3170 .info = snd_hdsp_info_sync_check, \
3171 .get = snd_hdsp_get_adat_sync_check \
3172}
3173
Takashi Iwai55e957d2005-11-17 14:52:13 +01003174static int hdsp_adat_sync_check(struct hdsp *hdsp, int idx)
Tim Blechmannf9ffc5d2009-02-20 19:38:16 +01003175{
Linus Torvalds1da177e2005-04-16 15:20:36 -07003176 int status = hdsp_read(hdsp, HDSP_statusRegister);
Tim Blechmannf9ffc5d2009-02-20 19:38:16 +01003177
Linus Torvalds1da177e2005-04-16 15:20:36 -07003178 if (status & (HDSP_Lock0>>idx)) {
Takashi Iwaib0b981192005-10-20 18:29:58 +02003179 if (status & (HDSP_Sync0>>idx))
Linus Torvalds1da177e2005-04-16 15:20:36 -07003180 return 2;
Takashi Iwaib0b981192005-10-20 18:29:58 +02003181 else
Tim Blechmannf9ffc5d2009-02-20 19:38:16 +01003182 return 1;
Takashi Iwaib0b981192005-10-20 18:29:58 +02003183 } else
Linus Torvalds1da177e2005-04-16 15:20:36 -07003184 return 0;
Tim Blechmannf9ffc5d2009-02-20 19:38:16 +01003185}
Linus Torvalds1da177e2005-04-16 15:20:36 -07003186
Takashi Iwai55e957d2005-11-17 14:52:13 +01003187static int snd_hdsp_get_adat_sync_check(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003188{
3189 int offset;
Takashi Iwai55e957d2005-11-17 14:52:13 +01003190 struct hdsp *hdsp = snd_kcontrol_chip(kcontrol);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003191
3192 offset = ucontrol->id.index - 1;
Takashi Iwaida3cec32008-08-08 17:12:14 +02003193 snd_BUG_ON(offset < 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003194
3195 switch (hdsp->io_type) {
3196 case Digiface:
3197 case H9652:
3198 if (offset >= 3)
3199 return -EINVAL;
3200 break;
3201 case Multiface:
3202 case H9632:
Tim Blechmannf9ffc5d2009-02-20 19:38:16 +01003203 if (offset >= 1)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003204 return -EINVAL;
3205 break;
3206 default:
3207 return -EIO;
3208 }
3209
3210 ucontrol->value.enumerated.item[0] = hdsp_adat_sync_check(hdsp, offset);
3211 return 0;
3212}
3213
Julian Cablee4b60882007-03-19 11:44:40 +01003214#define HDSP_DDS_OFFSET(xname, xindex) \
3215{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
3216 .name = xname, \
3217 .index = xindex, \
3218 .info = snd_hdsp_info_dds_offset, \
3219 .get = snd_hdsp_get_dds_offset, \
3220 .put = snd_hdsp_put_dds_offset \
3221}
3222
3223static int hdsp_dds_offset(struct hdsp *hdsp)
3224{
3225 u64 n;
Julian Cablee4b60882007-03-19 11:44:40 +01003226 unsigned int dds_value = hdsp->dds_value;
3227 int system_sample_rate = hdsp->system_sample_rate;
3228
Takashi Iwai2a3988f2007-10-16 14:26:32 +02003229 if (!dds_value)
3230 return 0;
3231
Julian Cablee4b60882007-03-19 11:44:40 +01003232 n = DDS_NUMERATOR;
3233 /*
3234 * dds_value = n / rate
3235 * rate = n / dds_value
3236 */
Takashi Iwai3f7440a2009-06-05 17:40:04 +02003237 n = div_u64(n, dds_value);
Julian Cablee4b60882007-03-19 11:44:40 +01003238 if (system_sample_rate >= 112000)
3239 n *= 4;
3240 else if (system_sample_rate >= 56000)
3241 n *= 2;
3242 return ((int)n) - system_sample_rate;
3243}
3244
3245static int hdsp_set_dds_offset(struct hdsp *hdsp, int offset_hz)
3246{
3247 int rate = hdsp->system_sample_rate + offset_hz;
3248 hdsp_set_dds_value(hdsp, rate);
3249 return 0;
3250}
3251
3252static int snd_hdsp_info_dds_offset(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
3253{
3254 uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
3255 uinfo->count = 1;
3256 uinfo->value.integer.min = -5000;
3257 uinfo->value.integer.max = 5000;
3258 return 0;
3259}
3260
3261static int snd_hdsp_get_dds_offset(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
3262{
3263 struct hdsp *hdsp = snd_kcontrol_chip(kcontrol);
Tim Blechmannf9ffc5d2009-02-20 19:38:16 +01003264
Julian Cablee4b60882007-03-19 11:44:40 +01003265 ucontrol->value.enumerated.item[0] = hdsp_dds_offset(hdsp);
3266 return 0;
3267}
3268
3269static int snd_hdsp_put_dds_offset(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
3270{
3271 struct hdsp *hdsp = snd_kcontrol_chip(kcontrol);
3272 int change;
3273 int val;
Tim Blechmannf9ffc5d2009-02-20 19:38:16 +01003274
Julian Cablee4b60882007-03-19 11:44:40 +01003275 if (!snd_hdsp_use_is_exclusive(hdsp))
3276 return -EBUSY;
3277 val = ucontrol->value.enumerated.item[0];
3278 spin_lock_irq(&hdsp->lock);
3279 if (val != hdsp_dds_offset(hdsp))
3280 change = (hdsp_set_dds_offset(hdsp, val) == 0) ? 1 : 0;
3281 else
3282 change = 0;
3283 spin_unlock_irq(&hdsp->lock);
3284 return change;
3285}
3286
Takashi Iwai55e957d2005-11-17 14:52:13 +01003287static struct snd_kcontrol_new snd_hdsp_9632_controls[] = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003288HDSP_DA_GAIN("DA Gain", 0),
3289HDSP_AD_GAIN("AD Gain", 0),
3290HDSP_PHONE_GAIN("Phones Gain", 0),
Julian Cablee4b60882007-03-19 11:44:40 +01003291HDSP_XLR_BREAKOUT_CABLE("XLR Breakout Cable", 0),
3292HDSP_DDS_OFFSET("DDS Sample Rate Offset", 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003293};
3294
Takashi Iwai55e957d2005-11-17 14:52:13 +01003295static struct snd_kcontrol_new snd_hdsp_controls[] = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003296{
Clemens Ladisch5549d542005-08-03 13:50:30 +02003297 .iface = SNDRV_CTL_ELEM_IFACE_PCM,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003298 .name = SNDRV_CTL_NAME_IEC958("",PLAYBACK,DEFAULT),
3299 .info = snd_hdsp_control_spdif_info,
3300 .get = snd_hdsp_control_spdif_get,
3301 .put = snd_hdsp_control_spdif_put,
3302},
3303{
3304 .access = SNDRV_CTL_ELEM_ACCESS_READWRITE | SNDRV_CTL_ELEM_ACCESS_INACTIVE,
Clemens Ladisch5549d542005-08-03 13:50:30 +02003305 .iface = SNDRV_CTL_ELEM_IFACE_PCM,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003306 .name = SNDRV_CTL_NAME_IEC958("",PLAYBACK,PCM_STREAM),
3307 .info = snd_hdsp_control_spdif_stream_info,
3308 .get = snd_hdsp_control_spdif_stream_get,
3309 .put = snd_hdsp_control_spdif_stream_put,
3310},
3311{
3312 .access = SNDRV_CTL_ELEM_ACCESS_READ,
Clemens Ladisch5549d542005-08-03 13:50:30 +02003313 .iface = SNDRV_CTL_ELEM_IFACE_PCM,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003314 .name = SNDRV_CTL_NAME_IEC958("",PLAYBACK,CON_MASK),
3315 .info = snd_hdsp_control_spdif_mask_info,
3316 .get = snd_hdsp_control_spdif_mask_get,
3317 .private_value = IEC958_AES0_NONAUDIO |
3318 IEC958_AES0_PROFESSIONAL |
Tim Blechmannf9ffc5d2009-02-20 19:38:16 +01003319 IEC958_AES0_CON_EMPHASIS,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003320},
3321{
3322 .access = SNDRV_CTL_ELEM_ACCESS_READ,
Clemens Ladisch5549d542005-08-03 13:50:30 +02003323 .iface = SNDRV_CTL_ELEM_IFACE_PCM,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003324 .name = SNDRV_CTL_NAME_IEC958("",PLAYBACK,PRO_MASK),
3325 .info = snd_hdsp_control_spdif_mask_info,
3326 .get = snd_hdsp_control_spdif_mask_get,
3327 .private_value = IEC958_AES0_NONAUDIO |
3328 IEC958_AES0_PROFESSIONAL |
3329 IEC958_AES0_PRO_EMPHASIS,
3330},
3331HDSP_MIXER("Mixer", 0),
3332HDSP_SPDIF_IN("IEC958 Input Connector", 0),
3333HDSP_SPDIF_OUT("IEC958 Output also on ADAT1", 0),
3334HDSP_SPDIF_PROFESSIONAL("IEC958 Professional Bit", 0),
3335HDSP_SPDIF_EMPHASIS("IEC958 Emphasis Bit", 0),
3336HDSP_SPDIF_NON_AUDIO("IEC958 Non-audio Bit", 0),
Tim Blechmannf9ffc5d2009-02-20 19:38:16 +01003337/* 'Sample Clock Source' complies with the alsa control naming scheme */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003338HDSP_CLOCK_SOURCE("Sample Clock Source", 0),
Takashi Iwaie3ea4d82005-07-04 18:12:39 +02003339{
Takashi Iwaie3ea4d82005-07-04 18:12:39 +02003340 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
3341 .name = "Sample Clock Source Locking",
3342 .info = snd_hdsp_info_clock_source_lock,
3343 .get = snd_hdsp_get_clock_source_lock,
3344 .put = snd_hdsp_put_clock_source_lock,
3345},
Linus Torvalds1da177e2005-04-16 15:20:36 -07003346HDSP_SYSTEM_CLOCK_MODE("System Clock Mode", 0),
3347HDSP_PREF_SYNC_REF("Preferred Sync Reference", 0),
3348HDSP_AUTOSYNC_REF("AutoSync Reference", 0),
3349HDSP_SPDIF_SAMPLE_RATE("SPDIF Sample Rate", 0),
3350HDSP_SYSTEM_SAMPLE_RATE("System Sample Rate", 0),
3351/* 'External Rate' complies with the alsa control naming scheme */
3352HDSP_AUTOSYNC_SAMPLE_RATE("External Rate", 0),
3353HDSP_WC_SYNC_CHECK("Word Clock Lock Status", 0),
3354HDSP_SPDIF_SYNC_CHECK("SPDIF Lock Status", 0),
3355HDSP_ADATSYNC_SYNC_CHECK("ADAT Sync Lock Status", 0),
3356HDSP_LINE_OUT("Line Out", 0),
3357HDSP_PRECISE_POINTER("Precise Pointer", 0),
3358HDSP_USE_MIDI_TASKLET("Use Midi Tasklet", 0),
3359};
3360
Florian Faber28b26e12010-12-01 12:14:47 +01003361
3362static int hdsp_rpm_input12(struct hdsp *hdsp)
3363{
3364 switch (hdsp->control_register & HDSP_RPM_Inp12) {
3365 case HDSP_RPM_Inp12_Phon_6dB:
3366 return 0;
3367 case HDSP_RPM_Inp12_Phon_n6dB:
3368 return 2;
3369 case HDSP_RPM_Inp12_Line_0dB:
3370 return 3;
3371 case HDSP_RPM_Inp12_Line_n6dB:
3372 return 4;
3373 }
3374 return 1;
3375}
3376
3377
3378static int snd_hdsp_get_rpm_input12(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
3379{
3380 struct hdsp *hdsp = snd_kcontrol_chip(kcontrol);
3381
3382 ucontrol->value.enumerated.item[0] = hdsp_rpm_input12(hdsp);
3383 return 0;
3384}
3385
3386
3387static int hdsp_set_rpm_input12(struct hdsp *hdsp, int mode)
3388{
3389 hdsp->control_register &= ~HDSP_RPM_Inp12;
3390 switch (mode) {
3391 case 0:
3392 hdsp->control_register |= HDSP_RPM_Inp12_Phon_6dB;
3393 break;
3394 case 1:
3395 break;
3396 case 2:
3397 hdsp->control_register |= HDSP_RPM_Inp12_Phon_n6dB;
3398 break;
3399 case 3:
3400 hdsp->control_register |= HDSP_RPM_Inp12_Line_0dB;
3401 break;
3402 case 4:
3403 hdsp->control_register |= HDSP_RPM_Inp12_Line_n6dB;
3404 break;
3405 default:
3406 return -1;
3407 }
3408
3409 hdsp_write(hdsp, HDSP_controlRegister, hdsp->control_register);
3410 return 0;
3411}
3412
3413
3414static int snd_hdsp_put_rpm_input12(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
3415{
3416 struct hdsp *hdsp = snd_kcontrol_chip(kcontrol);
3417 int change;
3418 int val;
3419
3420 if (!snd_hdsp_use_is_exclusive(hdsp))
3421 return -EBUSY;
3422 val = ucontrol->value.enumerated.item[0];
3423 if (val < 0)
3424 val = 0;
3425 if (val > 4)
3426 val = 4;
3427 spin_lock_irq(&hdsp->lock);
3428 if (val != hdsp_rpm_input12(hdsp))
3429 change = (hdsp_set_rpm_input12(hdsp, val) == 0) ? 1 : 0;
3430 else
3431 change = 0;
3432 spin_unlock_irq(&hdsp->lock);
3433 return change;
3434}
3435
3436
3437static int snd_hdsp_info_rpm_input(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
3438{
3439 static char *texts[] = {"Phono +6dB", "Phono 0dB", "Phono -6dB", "Line 0dB", "Line -6dB"};
3440
3441 uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
3442 uinfo->count = 1;
3443 uinfo->value.enumerated.items = 5;
3444 if (uinfo->value.enumerated.item >= uinfo->value.enumerated.items)
3445 uinfo->value.enumerated.item = uinfo->value.enumerated.items - 1;
3446 strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]);
3447 return 0;
3448}
3449
3450
3451static int hdsp_rpm_input34(struct hdsp *hdsp)
3452{
3453 switch (hdsp->control_register & HDSP_RPM_Inp34) {
3454 case HDSP_RPM_Inp34_Phon_6dB:
3455 return 0;
3456 case HDSP_RPM_Inp34_Phon_n6dB:
3457 return 2;
3458 case HDSP_RPM_Inp34_Line_0dB:
3459 return 3;
3460 case HDSP_RPM_Inp34_Line_n6dB:
3461 return 4;
3462 }
3463 return 1;
3464}
3465
3466
3467static int snd_hdsp_get_rpm_input34(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
3468{
3469 struct hdsp *hdsp = snd_kcontrol_chip(kcontrol);
3470
3471 ucontrol->value.enumerated.item[0] = hdsp_rpm_input34(hdsp);
3472 return 0;
3473}
3474
3475
3476static int hdsp_set_rpm_input34(struct hdsp *hdsp, int mode)
3477{
3478 hdsp->control_register &= ~HDSP_RPM_Inp34;
3479 switch (mode) {
3480 case 0:
3481 hdsp->control_register |= HDSP_RPM_Inp34_Phon_6dB;
3482 break;
3483 case 1:
3484 break;
3485 case 2:
3486 hdsp->control_register |= HDSP_RPM_Inp34_Phon_n6dB;
3487 break;
3488 case 3:
3489 hdsp->control_register |= HDSP_RPM_Inp34_Line_0dB;
3490 break;
3491 case 4:
3492 hdsp->control_register |= HDSP_RPM_Inp34_Line_n6dB;
3493 break;
3494 default:
3495 return -1;
3496 }
3497
3498 hdsp_write(hdsp, HDSP_controlRegister, hdsp->control_register);
3499 return 0;
3500}
3501
3502
3503static int snd_hdsp_put_rpm_input34(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
3504{
3505 struct hdsp *hdsp = snd_kcontrol_chip(kcontrol);
3506 int change;
3507 int val;
3508
3509 if (!snd_hdsp_use_is_exclusive(hdsp))
3510 return -EBUSY;
3511 val = ucontrol->value.enumerated.item[0];
3512 if (val < 0)
3513 val = 0;
3514 if (val > 4)
3515 val = 4;
3516 spin_lock_irq(&hdsp->lock);
3517 if (val != hdsp_rpm_input34(hdsp))
3518 change = (hdsp_set_rpm_input34(hdsp, val) == 0) ? 1 : 0;
3519 else
3520 change = 0;
3521 spin_unlock_irq(&hdsp->lock);
3522 return change;
3523}
3524
3525
3526/* RPM Bypass switch */
3527static int hdsp_rpm_bypass(struct hdsp *hdsp)
3528{
3529 return (hdsp->control_register & HDSP_RPM_Bypass) ? 1 : 0;
3530}
3531
3532
3533static int snd_hdsp_get_rpm_bypass(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
3534{
3535 struct hdsp *hdsp = snd_kcontrol_chip(kcontrol);
3536
3537 ucontrol->value.integer.value[0] = hdsp_rpm_bypass(hdsp);
3538 return 0;
3539}
3540
3541
3542static int hdsp_set_rpm_bypass(struct hdsp *hdsp, int on)
3543{
3544 if (on)
3545 hdsp->control_register |= HDSP_RPM_Bypass;
3546 else
3547 hdsp->control_register &= ~HDSP_RPM_Bypass;
3548 hdsp_write(hdsp, HDSP_controlRegister, hdsp->control_register);
3549 return 0;
3550}
3551
3552
3553static int snd_hdsp_put_rpm_bypass(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
3554{
3555 struct hdsp *hdsp = snd_kcontrol_chip(kcontrol);
3556 int change;
3557 unsigned int val;
3558
3559 if (!snd_hdsp_use_is_exclusive(hdsp))
3560 return -EBUSY;
3561 val = ucontrol->value.integer.value[0] & 1;
3562 spin_lock_irq(&hdsp->lock);
3563 change = (int)val != hdsp_rpm_bypass(hdsp);
3564 hdsp_set_rpm_bypass(hdsp, val);
3565 spin_unlock_irq(&hdsp->lock);
3566 return change;
3567}
3568
3569
3570static int snd_hdsp_info_rpm_bypass(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
3571{
3572 static char *texts[] = {"On", "Off"};
3573
3574 uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
3575 uinfo->count = 1;
3576 uinfo->value.enumerated.items = 2;
3577 if (uinfo->value.enumerated.item >= uinfo->value.enumerated.items)
3578 uinfo->value.enumerated.item = uinfo->value.enumerated.items - 1;
3579 strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]);
3580 return 0;
3581}
3582
3583
3584/* RPM Disconnect switch */
3585static int hdsp_rpm_disconnect(struct hdsp *hdsp)
3586{
3587 return (hdsp->control_register & HDSP_RPM_Disconnect) ? 1 : 0;
3588}
3589
3590
3591static int snd_hdsp_get_rpm_disconnect(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
3592{
3593 struct hdsp *hdsp = snd_kcontrol_chip(kcontrol);
3594
3595 ucontrol->value.integer.value[0] = hdsp_rpm_disconnect(hdsp);
3596 return 0;
3597}
3598
3599
3600static int hdsp_set_rpm_disconnect(struct hdsp *hdsp, int on)
3601{
3602 if (on)
3603 hdsp->control_register |= HDSP_RPM_Disconnect;
3604 else
3605 hdsp->control_register &= ~HDSP_RPM_Disconnect;
3606 hdsp_write(hdsp, HDSP_controlRegister, hdsp->control_register);
3607 return 0;
3608}
3609
3610
3611static int snd_hdsp_put_rpm_disconnect(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
3612{
3613 struct hdsp *hdsp = snd_kcontrol_chip(kcontrol);
3614 int change;
3615 unsigned int val;
3616
3617 if (!snd_hdsp_use_is_exclusive(hdsp))
3618 return -EBUSY;
3619 val = ucontrol->value.integer.value[0] & 1;
3620 spin_lock_irq(&hdsp->lock);
3621 change = (int)val != hdsp_rpm_disconnect(hdsp);
3622 hdsp_set_rpm_disconnect(hdsp, val);
3623 spin_unlock_irq(&hdsp->lock);
3624 return change;
3625}
3626
3627static int snd_hdsp_info_rpm_disconnect(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
3628{
3629 static char *texts[] = {"On", "Off"};
3630
3631 uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
3632 uinfo->count = 1;
3633 uinfo->value.enumerated.items = 2;
3634 if (uinfo->value.enumerated.item >= uinfo->value.enumerated.items)
3635 uinfo->value.enumerated.item = uinfo->value.enumerated.items - 1;
3636 strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]);
3637 return 0;
3638}
3639
3640static struct snd_kcontrol_new snd_hdsp_rpm_controls[] = {
3641 {
3642 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
3643 .name = "RPM Bypass",
3644 .get = snd_hdsp_get_rpm_bypass,
3645 .put = snd_hdsp_put_rpm_bypass,
3646 .info = snd_hdsp_info_rpm_bypass
3647 },
3648 {
3649 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
3650 .name = "RPM Disconnect",
3651 .get = snd_hdsp_get_rpm_disconnect,
3652 .put = snd_hdsp_put_rpm_disconnect,
3653 .info = snd_hdsp_info_rpm_disconnect
3654 },
3655 {
3656 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
3657 .name = "Input 1/2",
3658 .get = snd_hdsp_get_rpm_input12,
3659 .put = snd_hdsp_put_rpm_input12,
3660 .info = snd_hdsp_info_rpm_input
3661 },
3662 {
3663 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
3664 .name = "Input 3/4",
3665 .get = snd_hdsp_get_rpm_input34,
3666 .put = snd_hdsp_put_rpm_input34,
3667 .info = snd_hdsp_info_rpm_input
3668 },
3669 HDSP_SYSTEM_SAMPLE_RATE("System Sample Rate", 0),
3670 HDSP_MIXER("Mixer", 0)
3671};
3672
Takashi Iwai55e957d2005-11-17 14:52:13 +01003673static struct snd_kcontrol_new snd_hdsp_96xx_aeb = HDSP_AEB("Analog Extension Board", 0);
3674static struct snd_kcontrol_new snd_hdsp_adat_sync_check = HDSP_ADAT_SYNC_CHECK;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003675
Takashi Iwai55e957d2005-11-17 14:52:13 +01003676static int snd_hdsp_create_controls(struct snd_card *card, struct hdsp *hdsp)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003677{
3678 unsigned int idx;
3679 int err;
Takashi Iwai55e957d2005-11-17 14:52:13 +01003680 struct snd_kcontrol *kctl;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003681
Florian Faber28b26e12010-12-01 12:14:47 +01003682 if (hdsp->io_type == RPM) {
3683 /* RPM Bypass, Disconnect and Input switches */
3684 for (idx = 0; idx < ARRAY_SIZE(snd_hdsp_rpm_controls); idx++) {
3685 err = snd_ctl_add(card, kctl = snd_ctl_new1(&snd_hdsp_rpm_controls[idx], hdsp));
3686 if (err < 0)
3687 return err;
3688 }
3689 return 0;
3690 }
3691
Linus Torvalds1da177e2005-04-16 15:20:36 -07003692 for (idx = 0; idx < ARRAY_SIZE(snd_hdsp_controls); idx++) {
Takashi Iwaib0b981192005-10-20 18:29:58 +02003693 if ((err = snd_ctl_add(card, kctl = snd_ctl_new1(&snd_hdsp_controls[idx], hdsp))) < 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003694 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003695 if (idx == 1) /* IEC958 (S/PDIF) Stream */
3696 hdsp->spdif_ctl = kctl;
3697 }
3698
3699 /* ADAT SyncCheck status */
3700 snd_hdsp_adat_sync_check.name = "ADAT Lock Status";
3701 snd_hdsp_adat_sync_check.index = 1;
Takashi Iwaib0b981192005-10-20 18:29:58 +02003702 if ((err = snd_ctl_add (card, kctl = snd_ctl_new1(&snd_hdsp_adat_sync_check, hdsp))))
Linus Torvalds1da177e2005-04-16 15:20:36 -07003703 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003704 if (hdsp->io_type == Digiface || hdsp->io_type == H9652) {
3705 for (idx = 1; idx < 3; ++idx) {
3706 snd_hdsp_adat_sync_check.index = idx+1;
Takashi Iwaib0b981192005-10-20 18:29:58 +02003707 if ((err = snd_ctl_add (card, kctl = snd_ctl_new1(&snd_hdsp_adat_sync_check, hdsp))))
Linus Torvalds1da177e2005-04-16 15:20:36 -07003708 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003709 }
3710 }
Tim Blechmannf9ffc5d2009-02-20 19:38:16 +01003711
Linus Torvalds1da177e2005-04-16 15:20:36 -07003712 /* DA, AD and Phone gain and XLR breakout cable controls for H9632 cards */
3713 if (hdsp->io_type == H9632) {
3714 for (idx = 0; idx < ARRAY_SIZE(snd_hdsp_9632_controls); idx++) {
Takashi Iwaib0b981192005-10-20 18:29:58 +02003715 if ((err = snd_ctl_add(card, kctl = snd_ctl_new1(&snd_hdsp_9632_controls[idx], hdsp))) < 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003716 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003717 }
3718 }
3719
3720 /* AEB control for H96xx card */
3721 if (hdsp->io_type == H9632 || hdsp->io_type == H9652) {
Takashi Iwaib0b981192005-10-20 18:29:58 +02003722 if ((err = snd_ctl_add(card, kctl = snd_ctl_new1(&snd_hdsp_96xx_aeb, hdsp))) < 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003723 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003724 }
3725
3726 return 0;
3727}
3728
3729/*------------------------------------------------------------
Tim Blechmannf9ffc5d2009-02-20 19:38:16 +01003730 /proc interface
Linus Torvalds1da177e2005-04-16 15:20:36 -07003731 ------------------------------------------------------------*/
3732
3733static void
Takashi Iwai55e957d2005-11-17 14:52:13 +01003734snd_hdsp_proc_read(struct snd_info_entry *entry, struct snd_info_buffer *buffer)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003735{
Joe Perches9fe856e2010-09-04 18:52:54 -07003736 struct hdsp *hdsp = entry->private_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003737 unsigned int status;
3738 unsigned int status2;
3739 char *pref_sync_ref;
3740 char *autosync_ref;
3741 char *system_clock_mode;
3742 char *clock_source;
3743 int x;
3744
Tim Blechmannc18bc9b2009-08-12 18:21:30 +02003745 status = hdsp_read(hdsp, HDSP_statusRegister);
3746 status2 = hdsp_read(hdsp, HDSP_status2Register);
3747
3748 snd_iprintf(buffer, "%s (Card #%d)\n", hdsp->card_name,
3749 hdsp->card->number + 1);
3750 snd_iprintf(buffer, "Buffers: capture %p playback %p\n",
3751 hdsp->capture_buffer, hdsp->playback_buffer);
3752 snd_iprintf(buffer, "IRQ: %d Registers bus: 0x%lx VM: 0x%lx\n",
3753 hdsp->irq, hdsp->port, (unsigned long)hdsp->iobase);
3754 snd_iprintf(buffer, "Control register: 0x%x\n", hdsp->control_register);
3755 snd_iprintf(buffer, "Control2 register: 0x%x\n",
3756 hdsp->control2_register);
3757 snd_iprintf(buffer, "Status register: 0x%x\n", status);
3758 snd_iprintf(buffer, "Status2 register: 0x%x\n", status2);
3759
3760 if (hdsp_check_for_iobox(hdsp)) {
3761 snd_iprintf(buffer, "No I/O box connected.\n"
3762 "Please connect one and upload firmware.\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07003763 return;
Tim Blechmannc18bc9b2009-08-12 18:21:30 +02003764 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003765
Takashi Iwaib0b981192005-10-20 18:29:58 +02003766 if (hdsp_check_for_firmware(hdsp, 0)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003767 if (hdsp->state & HDSP_FirmwareCached) {
3768 if (snd_hdsp_load_firmware_from_cache(hdsp) != 0) {
Tim Blechmannc18bc9b2009-08-12 18:21:30 +02003769 snd_iprintf(buffer, "Firmware loading from "
3770 "cache failed, "
3771 "please upload manually.\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07003772 return;
3773 }
3774 } else {
Takashi Iwai311e70a2006-09-06 12:13:37 +02003775 int err = -EINVAL;
Takashi Iwai311e70a2006-09-06 12:13:37 +02003776 err = hdsp_request_fw_loader(hdsp);
Takashi Iwai311e70a2006-09-06 12:13:37 +02003777 if (err < 0) {
3778 snd_iprintf(buffer,
3779 "No firmware loaded nor cached, "
3780 "please upload firmware.\n");
3781 return;
3782 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003783 }
3784 }
Tim Blechmannf9ffc5d2009-02-20 19:38:16 +01003785
Linus Torvalds1da177e2005-04-16 15:20:36 -07003786 snd_iprintf(buffer, "FIFO status: %d\n", hdsp_read(hdsp, HDSP_fifoStatus) & 0xff);
3787 snd_iprintf(buffer, "MIDI1 Output status: 0x%x\n", hdsp_read(hdsp, HDSP_midiStatusOut0));
3788 snd_iprintf(buffer, "MIDI1 Input status: 0x%x\n", hdsp_read(hdsp, HDSP_midiStatusIn0));
3789 snd_iprintf(buffer, "MIDI2 Output status: 0x%x\n", hdsp_read(hdsp, HDSP_midiStatusOut1));
3790 snd_iprintf(buffer, "MIDI2 Input status: 0x%x\n", hdsp_read(hdsp, HDSP_midiStatusIn1));
3791 snd_iprintf(buffer, "Use Midi Tasklet: %s\n", hdsp->use_midi_tasklet ? "on" : "off");
3792
3793 snd_iprintf(buffer, "\n");
3794
3795 x = 1 << (6 + hdsp_decode_latency(hdsp->control_register & HDSP_LatencyMask));
3796
3797 snd_iprintf(buffer, "Buffer Size (Latency): %d samples (2 periods of %lu bytes)\n", x, (unsigned long) hdsp->period_bytes);
3798 snd_iprintf(buffer, "Hardware pointer (frames): %ld\n", hdsp_hw_pointer(hdsp));
3799 snd_iprintf(buffer, "Precise pointer: %s\n", hdsp->precise_ptr ? "on" : "off");
3800 snd_iprintf(buffer, "Line out: %s\n", (hdsp->control_register & HDSP_LineOut) ? "on" : "off");
3801
3802 snd_iprintf(buffer, "Firmware version: %d\n", (status2&HDSP_version0)|(status2&HDSP_version1)<<1|(status2&HDSP_version2)<<2);
3803
3804 snd_iprintf(buffer, "\n");
3805
Linus Torvalds1da177e2005-04-16 15:20:36 -07003806 switch (hdsp_clock_source(hdsp)) {
3807 case HDSP_CLOCK_SOURCE_AUTOSYNC:
3808 clock_source = "AutoSync";
3809 break;
3810 case HDSP_CLOCK_SOURCE_INTERNAL_32KHZ:
3811 clock_source = "Internal 32 kHz";
3812 break;
3813 case HDSP_CLOCK_SOURCE_INTERNAL_44_1KHZ:
3814 clock_source = "Internal 44.1 kHz";
3815 break;
3816 case HDSP_CLOCK_SOURCE_INTERNAL_48KHZ:
3817 clock_source = "Internal 48 kHz";
3818 break;
3819 case HDSP_CLOCK_SOURCE_INTERNAL_64KHZ:
3820 clock_source = "Internal 64 kHz";
3821 break;
3822 case HDSP_CLOCK_SOURCE_INTERNAL_88_2KHZ:
3823 clock_source = "Internal 88.2 kHz";
3824 break;
3825 case HDSP_CLOCK_SOURCE_INTERNAL_96KHZ:
3826 clock_source = "Internal 96 kHz";
3827 break;
3828 case HDSP_CLOCK_SOURCE_INTERNAL_128KHZ:
3829 clock_source = "Internal 128 kHz";
3830 break;
3831 case HDSP_CLOCK_SOURCE_INTERNAL_176_4KHZ:
3832 clock_source = "Internal 176.4 kHz";
3833 break;
3834 case HDSP_CLOCK_SOURCE_INTERNAL_192KHZ:
3835 clock_source = "Internal 192 kHz";
Tim Blechmannf9ffc5d2009-02-20 19:38:16 +01003836 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003837 default:
Tim Blechmannf9ffc5d2009-02-20 19:38:16 +01003838 clock_source = "Error";
Linus Torvalds1da177e2005-04-16 15:20:36 -07003839 }
3840 snd_iprintf (buffer, "Sample Clock Source: %s\n", clock_source);
Tim Blechmannf9ffc5d2009-02-20 19:38:16 +01003841
Takashi Iwaib0b981192005-10-20 18:29:58 +02003842 if (hdsp_system_clock_mode(hdsp))
Linus Torvalds1da177e2005-04-16 15:20:36 -07003843 system_clock_mode = "Slave";
Takashi Iwaib0b981192005-10-20 18:29:58 +02003844 else
Linus Torvalds1da177e2005-04-16 15:20:36 -07003845 system_clock_mode = "Master";
Tim Blechmannf9ffc5d2009-02-20 19:38:16 +01003846
Linus Torvalds1da177e2005-04-16 15:20:36 -07003847 switch (hdsp_pref_sync_ref (hdsp)) {
3848 case HDSP_SYNC_FROM_WORD:
3849 pref_sync_ref = "Word Clock";
3850 break;
3851 case HDSP_SYNC_FROM_ADAT_SYNC:
3852 pref_sync_ref = "ADAT Sync";
3853 break;
3854 case HDSP_SYNC_FROM_SPDIF:
3855 pref_sync_ref = "SPDIF";
3856 break;
3857 case HDSP_SYNC_FROM_ADAT1:
3858 pref_sync_ref = "ADAT1";
3859 break;
3860 case HDSP_SYNC_FROM_ADAT2:
3861 pref_sync_ref = "ADAT2";
3862 break;
3863 case HDSP_SYNC_FROM_ADAT3:
3864 pref_sync_ref = "ADAT3";
3865 break;
3866 default:
3867 pref_sync_ref = "Word Clock";
3868 break;
3869 }
3870 snd_iprintf (buffer, "Preferred Sync Reference: %s\n", pref_sync_ref);
Tim Blechmannf9ffc5d2009-02-20 19:38:16 +01003871
Linus Torvalds1da177e2005-04-16 15:20:36 -07003872 switch (hdsp_autosync_ref (hdsp)) {
3873 case HDSP_AUTOSYNC_FROM_WORD:
3874 autosync_ref = "Word Clock";
3875 break;
3876 case HDSP_AUTOSYNC_FROM_ADAT_SYNC:
3877 autosync_ref = "ADAT Sync";
3878 break;
3879 case HDSP_AUTOSYNC_FROM_SPDIF:
3880 autosync_ref = "SPDIF";
3881 break;
3882 case HDSP_AUTOSYNC_FROM_NONE:
3883 autosync_ref = "None";
Tim Blechmannf9ffc5d2009-02-20 19:38:16 +01003884 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003885 case HDSP_AUTOSYNC_FROM_ADAT1:
3886 autosync_ref = "ADAT1";
3887 break;
3888 case HDSP_AUTOSYNC_FROM_ADAT2:
3889 autosync_ref = "ADAT2";
3890 break;
3891 case HDSP_AUTOSYNC_FROM_ADAT3:
3892 autosync_ref = "ADAT3";
3893 break;
3894 default:
3895 autosync_ref = "---";
3896 break;
3897 }
3898 snd_iprintf (buffer, "AutoSync Reference: %s\n", autosync_ref);
Tim Blechmannf9ffc5d2009-02-20 19:38:16 +01003899
Linus Torvalds1da177e2005-04-16 15:20:36 -07003900 snd_iprintf (buffer, "AutoSync Frequency: %d\n", hdsp_external_sample_rate(hdsp));
Tim Blechmannf9ffc5d2009-02-20 19:38:16 +01003901
Linus Torvalds1da177e2005-04-16 15:20:36 -07003902 snd_iprintf (buffer, "System Clock Mode: %s\n", system_clock_mode);
3903
3904 snd_iprintf (buffer, "System Clock Frequency: %d\n", hdsp->system_sample_rate);
Takashi Iwaie3ea4d82005-07-04 18:12:39 +02003905 snd_iprintf (buffer, "System Clock Locked: %s\n", hdsp->clock_source_locked ? "Yes" : "No");
Tim Blechmannf9ffc5d2009-02-20 19:38:16 +01003906
Linus Torvalds1da177e2005-04-16 15:20:36 -07003907 snd_iprintf(buffer, "\n");
3908
Florian Faber28b26e12010-12-01 12:14:47 +01003909 if (hdsp->io_type != RPM) {
3910 switch (hdsp_spdif_in(hdsp)) {
3911 case HDSP_SPDIFIN_OPTICAL:
3912 snd_iprintf(buffer, "IEC958 input: Optical\n");
3913 break;
3914 case HDSP_SPDIFIN_COAXIAL:
3915 snd_iprintf(buffer, "IEC958 input: Coaxial\n");
3916 break;
3917 case HDSP_SPDIFIN_INTERNAL:
3918 snd_iprintf(buffer, "IEC958 input: Internal\n");
3919 break;
3920 case HDSP_SPDIFIN_AES:
3921 snd_iprintf(buffer, "IEC958 input: AES\n");
3922 break;
3923 default:
3924 snd_iprintf(buffer, "IEC958 input: ???\n");
3925 break;
3926 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003927 }
Tim Blechmannf9ffc5d2009-02-20 19:38:16 +01003928
Florian Faber28b26e12010-12-01 12:14:47 +01003929 if (RPM == hdsp->io_type) {
3930 if (hdsp->control_register & HDSP_RPM_Bypass)
3931 snd_iprintf(buffer, "RPM Bypass: disabled\n");
3932 else
3933 snd_iprintf(buffer, "RPM Bypass: enabled\n");
3934 if (hdsp->control_register & HDSP_RPM_Disconnect)
3935 snd_iprintf(buffer, "RPM disconnected\n");
3936 else
3937 snd_iprintf(buffer, "RPM connected\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07003938
Florian Faber28b26e12010-12-01 12:14:47 +01003939 switch (hdsp->control_register & HDSP_RPM_Inp12) {
3940 case HDSP_RPM_Inp12_Phon_6dB:
3941 snd_iprintf(buffer, "Input 1/2: Phono, 6dB\n");
3942 break;
3943 case HDSP_RPM_Inp12_Phon_0dB:
3944 snd_iprintf(buffer, "Input 1/2: Phono, 0dB\n");
3945 break;
3946 case HDSP_RPM_Inp12_Phon_n6dB:
3947 snd_iprintf(buffer, "Input 1/2: Phono, -6dB\n");
3948 break;
3949 case HDSP_RPM_Inp12_Line_0dB:
3950 snd_iprintf(buffer, "Input 1/2: Line, 0dB\n");
3951 break;
3952 case HDSP_RPM_Inp12_Line_n6dB:
3953 snd_iprintf(buffer, "Input 1/2: Line, -6dB\n");
3954 break;
3955 default:
3956 snd_iprintf(buffer, "Input 1/2: ???\n");
3957 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003958
Florian Faber28b26e12010-12-01 12:14:47 +01003959 switch (hdsp->control_register & HDSP_RPM_Inp34) {
3960 case HDSP_RPM_Inp34_Phon_6dB:
3961 snd_iprintf(buffer, "Input 3/4: Phono, 6dB\n");
3962 break;
3963 case HDSP_RPM_Inp34_Phon_0dB:
3964 snd_iprintf(buffer, "Input 3/4: Phono, 0dB\n");
3965 break;
3966 case HDSP_RPM_Inp34_Phon_n6dB:
3967 snd_iprintf(buffer, "Input 3/4: Phono, -6dB\n");
3968 break;
3969 case HDSP_RPM_Inp34_Line_0dB:
3970 snd_iprintf(buffer, "Input 3/4: Line, 0dB\n");
3971 break;
3972 case HDSP_RPM_Inp34_Line_n6dB:
3973 snd_iprintf(buffer, "Input 3/4: Line, -6dB\n");
3974 break;
3975 default:
3976 snd_iprintf(buffer, "Input 3/4: ???\n");
3977 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003978
Florian Faber28b26e12010-12-01 12:14:47 +01003979 } else {
3980 if (hdsp->control_register & HDSP_SPDIFOpticalOut)
3981 snd_iprintf(buffer, "IEC958 output: Coaxial & ADAT1\n");
3982 else
3983 snd_iprintf(buffer, "IEC958 output: Coaxial only\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07003984
Florian Faber28b26e12010-12-01 12:14:47 +01003985 if (hdsp->control_register & HDSP_SPDIFProfessional)
3986 snd_iprintf(buffer, "IEC958 quality: Professional\n");
3987 else
3988 snd_iprintf(buffer, "IEC958 quality: Consumer\n");
3989
3990 if (hdsp->control_register & HDSP_SPDIFEmphasis)
3991 snd_iprintf(buffer, "IEC958 emphasis: on\n");
3992 else
3993 snd_iprintf(buffer, "IEC958 emphasis: off\n");
3994
3995 if (hdsp->control_register & HDSP_SPDIFNonAudio)
3996 snd_iprintf(buffer, "IEC958 NonAudio: on\n");
3997 else
3998 snd_iprintf(buffer, "IEC958 NonAudio: off\n");
3999 x = hdsp_spdif_sample_rate(hdsp);
4000 if (x != 0)
4001 snd_iprintf(buffer, "IEC958 sample rate: %d\n", x);
4002 else
4003 snd_iprintf(buffer, "IEC958 sample rate: Error flag set\n");
4004 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004005 snd_iprintf(buffer, "\n");
4006
4007 /* Sync Check */
4008 x = status & HDSP_Sync0;
Takashi Iwaib0b981192005-10-20 18:29:58 +02004009 if (status & HDSP_Lock0)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004010 snd_iprintf(buffer, "ADAT1: %s\n", x ? "Sync" : "Lock");
Takashi Iwaib0b981192005-10-20 18:29:58 +02004011 else
Linus Torvalds1da177e2005-04-16 15:20:36 -07004012 snd_iprintf(buffer, "ADAT1: No Lock\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07004013
4014 switch (hdsp->io_type) {
4015 case Digiface:
4016 case H9652:
4017 x = status & HDSP_Sync1;
Takashi Iwaib0b981192005-10-20 18:29:58 +02004018 if (status & HDSP_Lock1)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004019 snd_iprintf(buffer, "ADAT2: %s\n", x ? "Sync" : "Lock");
Takashi Iwaib0b981192005-10-20 18:29:58 +02004020 else
Linus Torvalds1da177e2005-04-16 15:20:36 -07004021 snd_iprintf(buffer, "ADAT2: No Lock\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07004022 x = status & HDSP_Sync2;
Takashi Iwaib0b981192005-10-20 18:29:58 +02004023 if (status & HDSP_Lock2)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004024 snd_iprintf(buffer, "ADAT3: %s\n", x ? "Sync" : "Lock");
Takashi Iwaib0b981192005-10-20 18:29:58 +02004025 else
Linus Torvalds1da177e2005-04-16 15:20:36 -07004026 snd_iprintf(buffer, "ADAT3: No Lock\n");
Takashi Iwaib0b981192005-10-20 18:29:58 +02004027 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004028 default:
4029 /* relax */
4030 break;
4031 }
4032
4033 x = status & HDSP_SPDIFSync;
Takashi Iwaib0b981192005-10-20 18:29:58 +02004034 if (status & HDSP_SPDIFErrorFlag)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004035 snd_iprintf (buffer, "SPDIF: No Lock\n");
Takashi Iwaib0b981192005-10-20 18:29:58 +02004036 else
Linus Torvalds1da177e2005-04-16 15:20:36 -07004037 snd_iprintf (buffer, "SPDIF: %s\n", x ? "Sync" : "Lock");
Tim Blechmannf9ffc5d2009-02-20 19:38:16 +01004038
Linus Torvalds1da177e2005-04-16 15:20:36 -07004039 x = status2 & HDSP_wc_sync;
Takashi Iwaib0b981192005-10-20 18:29:58 +02004040 if (status2 & HDSP_wc_lock)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004041 snd_iprintf (buffer, "Word Clock: %s\n", x ? "Sync" : "Lock");
Takashi Iwaib0b981192005-10-20 18:29:58 +02004042 else
Linus Torvalds1da177e2005-04-16 15:20:36 -07004043 snd_iprintf (buffer, "Word Clock: No Lock\n");
Tim Blechmannf9ffc5d2009-02-20 19:38:16 +01004044
Linus Torvalds1da177e2005-04-16 15:20:36 -07004045 x = status & HDSP_TimecodeSync;
Takashi Iwaib0b981192005-10-20 18:29:58 +02004046 if (status & HDSP_TimecodeLock)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004047 snd_iprintf(buffer, "ADAT Sync: %s\n", x ? "Sync" : "Lock");
Takashi Iwaib0b981192005-10-20 18:29:58 +02004048 else
Linus Torvalds1da177e2005-04-16 15:20:36 -07004049 snd_iprintf(buffer, "ADAT Sync: No Lock\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07004050
4051 snd_iprintf(buffer, "\n");
Tim Blechmannf9ffc5d2009-02-20 19:38:16 +01004052
Linus Torvalds1da177e2005-04-16 15:20:36 -07004053 /* Informations about H9632 specific controls */
4054 if (hdsp->io_type == H9632) {
4055 char *tmp;
Tim Blechmannf9ffc5d2009-02-20 19:38:16 +01004056
Linus Torvalds1da177e2005-04-16 15:20:36 -07004057 switch (hdsp_ad_gain(hdsp)) {
4058 case 0:
4059 tmp = "-10 dBV";
4060 break;
4061 case 1:
4062 tmp = "+4 dBu";
4063 break;
4064 default:
4065 tmp = "Lo Gain";
4066 break;
4067 }
4068 snd_iprintf(buffer, "AD Gain : %s\n", tmp);
4069
4070 switch (hdsp_da_gain(hdsp)) {
4071 case 0:
4072 tmp = "Hi Gain";
4073 break;
4074 case 1:
4075 tmp = "+4 dBu";
4076 break;
4077 default:
4078 tmp = "-10 dBV";
4079 break;
4080 }
4081 snd_iprintf(buffer, "DA Gain : %s\n", tmp);
Tim Blechmannf9ffc5d2009-02-20 19:38:16 +01004082
Linus Torvalds1da177e2005-04-16 15:20:36 -07004083 switch (hdsp_phone_gain(hdsp)) {
4084 case 0:
4085 tmp = "0 dB";
4086 break;
4087 case 1:
4088 tmp = "-6 dB";
4089 break;
4090 default:
4091 tmp = "-12 dB";
4092 break;
4093 }
4094 snd_iprintf(buffer, "Phones Gain : %s\n", tmp);
4095
Tim Blechmannf9ffc5d2009-02-20 19:38:16 +01004096 snd_iprintf(buffer, "XLR Breakout Cable : %s\n", hdsp_xlr_breakout_cable(hdsp) ? "yes" : "no");
4097
Takashi Iwaib0b981192005-10-20 18:29:58 +02004098 if (hdsp->control_register & HDSP_AnalogExtensionBoard)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004099 snd_iprintf(buffer, "AEB : on (ADAT1 internal)\n");
Takashi Iwaib0b981192005-10-20 18:29:58 +02004100 else
Linus Torvalds1da177e2005-04-16 15:20:36 -07004101 snd_iprintf(buffer, "AEB : off (ADAT1 external)\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07004102 snd_iprintf(buffer, "\n");
4103 }
4104
4105}
4106
Randy Dunlap1374f8c2008-01-16 14:55:42 +01004107static void snd_hdsp_proc_init(struct hdsp *hdsp)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004108{
Takashi Iwai55e957d2005-11-17 14:52:13 +01004109 struct snd_info_entry *entry;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004110
4111 if (! snd_card_proc_new(hdsp->card, "hdsp", &entry))
Takashi Iwaibf850202006-04-28 15:13:41 +02004112 snd_info_set_text_ops(entry, hdsp, snd_hdsp_proc_read);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004113}
4114
Takashi Iwai55e957d2005-11-17 14:52:13 +01004115static void snd_hdsp_free_buffers(struct hdsp *hdsp)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004116{
4117 snd_hammerfall_free_buffer(&hdsp->capture_dma_buf, hdsp->pci);
4118 snd_hammerfall_free_buffer(&hdsp->playback_dma_buf, hdsp->pci);
4119}
4120
Bill Pembertone23e7a12012-12-06 12:35:10 -05004121static int snd_hdsp_initialize_memory(struct hdsp *hdsp)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004122{
4123 unsigned long pb_bus, cb_bus;
4124
4125 if (snd_hammerfall_get_buffer(hdsp->pci, &hdsp->capture_dma_buf, HDSP_DMA_AREA_BYTES) < 0 ||
4126 snd_hammerfall_get_buffer(hdsp->pci, &hdsp->playback_dma_buf, HDSP_DMA_AREA_BYTES) < 0) {
4127 if (hdsp->capture_dma_buf.area)
4128 snd_dma_free_pages(&hdsp->capture_dma_buf);
4129 printk(KERN_ERR "%s: no buffers available\n", hdsp->card_name);
4130 return -ENOMEM;
4131 }
4132
4133 /* Align to bus-space 64K boundary */
4134
Clemens Ladisch7ab39922006-10-09 08:13:32 +02004135 cb_bus = ALIGN(hdsp->capture_dma_buf.addr, 0x10000ul);
4136 pb_bus = ALIGN(hdsp->playback_dma_buf.addr, 0x10000ul);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004137
4138 /* Tell the card where it is */
4139
4140 hdsp_write(hdsp, HDSP_inputBufferAddress, cb_bus);
4141 hdsp_write(hdsp, HDSP_outputBufferAddress, pb_bus);
4142
4143 hdsp->capture_buffer = hdsp->capture_dma_buf.area + (cb_bus - hdsp->capture_dma_buf.addr);
4144 hdsp->playback_buffer = hdsp->playback_dma_buf.area + (pb_bus - hdsp->playback_dma_buf.addr);
4145
4146 return 0;
4147}
4148
Takashi Iwai55e957d2005-11-17 14:52:13 +01004149static int snd_hdsp_set_defaults(struct hdsp *hdsp)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004150{
4151 unsigned int i;
4152
4153 /* ASSUMPTION: hdsp->lock is either held, or
4154 there is no need to hold it (e.g. during module
Joe Perches561de312007-12-18 13:13:47 +01004155 initialization).
Linus Torvalds1da177e2005-04-16 15:20:36 -07004156 */
4157
4158 /* set defaults:
4159
Tim Blechmannf9ffc5d2009-02-20 19:38:16 +01004160 SPDIF Input via Coax
Linus Torvalds1da177e2005-04-16 15:20:36 -07004161 Master clock mode
4162 maximum latency (7 => 2^7 = 8192 samples, 64Kbyte buffer,
4163 which implies 2 4096 sample, 32Kbyte periods).
Tim Blechmannf9ffc5d2009-02-20 19:38:16 +01004164 Enable line out.
Linus Torvalds1da177e2005-04-16 15:20:36 -07004165 */
4166
Tim Blechmannf9ffc5d2009-02-20 19:38:16 +01004167 hdsp->control_register = HDSP_ClockModeMaster |
4168 HDSP_SPDIFInputCoaxial |
4169 hdsp_encode_latency(7) |
Linus Torvalds1da177e2005-04-16 15:20:36 -07004170 HDSP_LineOut;
Tim Blechmannf9ffc5d2009-02-20 19:38:16 +01004171
Linus Torvalds1da177e2005-04-16 15:20:36 -07004172
4173 hdsp_write(hdsp, HDSP_controlRegister, hdsp->control_register);
4174
4175#ifdef SNDRV_BIG_ENDIAN
4176 hdsp->control2_register = HDSP_BIGENDIAN_MODE;
4177#else
4178 hdsp->control2_register = 0;
4179#endif
Takashi Iwaib0b981192005-10-20 18:29:58 +02004180 if (hdsp->io_type == H9652)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004181 snd_hdsp_9652_enable_mixer (hdsp);
Takashi Iwaib0b981192005-10-20 18:29:58 +02004182 else
4183 hdsp_write (hdsp, HDSP_control2Reg, hdsp->control2_register);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004184
4185 hdsp_reset_hw_pointer(hdsp);
4186 hdsp_compute_period_size(hdsp);
4187
4188 /* silence everything */
Tim Blechmannf9ffc5d2009-02-20 19:38:16 +01004189
Takashi Iwaib0b981192005-10-20 18:29:58 +02004190 for (i = 0; i < HDSP_MATRIX_MIXER_SIZE; ++i)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004191 hdsp->mixer_matrix[i] = MINUS_INFINITY_GAIN;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004192
4193 for (i = 0; i < ((hdsp->io_type == H9652 || hdsp->io_type == H9632) ? 1352 : HDSP_MATRIX_MIXER_SIZE); ++i) {
Takashi Iwaib0b981192005-10-20 18:29:58 +02004194 if (hdsp_write_gain (hdsp, i, MINUS_INFINITY_GAIN))
Linus Torvalds1da177e2005-04-16 15:20:36 -07004195 return -EIO;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004196 }
Tim Blechmannf9ffc5d2009-02-20 19:38:16 +01004197
Linus Torvalds1da177e2005-04-16 15:20:36 -07004198 /* H9632 specific defaults */
4199 if (hdsp->io_type == H9632) {
4200 hdsp->control_register |= (HDSP_DAGainPlus4dBu | HDSP_ADGainPlus4dBu | HDSP_PhoneGain0dB);
4201 hdsp_write(hdsp, HDSP_controlRegister, hdsp->control_register);
4202 }
4203
4204 /* set a default rate so that the channel map is set up.
4205 */
4206
4207 hdsp_set_rate(hdsp, 48000, 1);
4208
4209 return 0;
4210}
4211
4212static void hdsp_midi_tasklet(unsigned long arg)
4213{
Takashi Iwai55e957d2005-11-17 14:52:13 +01004214 struct hdsp *hdsp = (struct hdsp *)arg;
Tim Blechmannf9ffc5d2009-02-20 19:38:16 +01004215
Takashi Iwaib0b981192005-10-20 18:29:58 +02004216 if (hdsp->midi[0].pending)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004217 snd_hdsp_midi_input_read (&hdsp->midi[0]);
Takashi Iwaib0b981192005-10-20 18:29:58 +02004218 if (hdsp->midi[1].pending)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004219 snd_hdsp_midi_input_read (&hdsp->midi[1]);
Tim Blechmannf9ffc5d2009-02-20 19:38:16 +01004220}
Linus Torvalds1da177e2005-04-16 15:20:36 -07004221
David Howells7d12e782006-10-05 14:55:46 +01004222static irqreturn_t snd_hdsp_interrupt(int irq, void *dev_id)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004223{
Takashi Iwai55e957d2005-11-17 14:52:13 +01004224 struct hdsp *hdsp = (struct hdsp *) dev_id;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004225 unsigned int status;
4226 int audio;
4227 int midi0;
4228 int midi1;
4229 unsigned int midi0status;
4230 unsigned int midi1status;
4231 int schedule = 0;
Tim Blechmannf9ffc5d2009-02-20 19:38:16 +01004232
Linus Torvalds1da177e2005-04-16 15:20:36 -07004233 status = hdsp_read(hdsp, HDSP_statusRegister);
4234
4235 audio = status & HDSP_audioIRQPending;
4236 midi0 = status & HDSP_midi0IRQPending;
4237 midi1 = status & HDSP_midi1IRQPending;
4238
Takashi Iwaib0b981192005-10-20 18:29:58 +02004239 if (!audio && !midi0 && !midi1)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004240 return IRQ_NONE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004241
4242 hdsp_write(hdsp, HDSP_interruptConfirmation, 0);
4243
4244 midi0status = hdsp_read (hdsp, HDSP_midiStatusIn0) & 0xff;
4245 midi1status = hdsp_read (hdsp, HDSP_midiStatusIn1) & 0xff;
Tim Blechmannf9ffc5d2009-02-20 19:38:16 +01004246
Takashi Iwaic2503cd2009-03-05 09:37:40 +01004247 if (!(hdsp->state & HDSP_InitializationComplete))
4248 return IRQ_HANDLED;
4249
Linus Torvalds1da177e2005-04-16 15:20:36 -07004250 if (audio) {
Takashi Iwaib0b981192005-10-20 18:29:58 +02004251 if (hdsp->capture_substream)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004252 snd_pcm_period_elapsed(hdsp->pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream);
Tim Blechmannf9ffc5d2009-02-20 19:38:16 +01004253
Takashi Iwaib0b981192005-10-20 18:29:58 +02004254 if (hdsp->playback_substream)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004255 snd_pcm_period_elapsed(hdsp->pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004256 }
Tim Blechmannf9ffc5d2009-02-20 19:38:16 +01004257
Linus Torvalds1da177e2005-04-16 15:20:36 -07004258 if (midi0 && midi0status) {
4259 if (hdsp->use_midi_tasklet) {
4260 /* we disable interrupts for this input until processing is done */
4261 hdsp->control_register &= ~HDSP_Midi0InterruptEnable;
4262 hdsp_write(hdsp, HDSP_controlRegister, hdsp->control_register);
4263 hdsp->midi[0].pending = 1;
4264 schedule = 1;
4265 } else {
4266 snd_hdsp_midi_input_read (&hdsp->midi[0]);
4267 }
4268 }
Florian Faber28b26e12010-12-01 12:14:47 +01004269 if (hdsp->io_type != Multiface && hdsp->io_type != RPM && hdsp->io_type != H9632 && midi1 && midi1status) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004270 if (hdsp->use_midi_tasklet) {
4271 /* we disable interrupts for this input until processing is done */
4272 hdsp->control_register &= ~HDSP_Midi1InterruptEnable;
4273 hdsp_write(hdsp, HDSP_controlRegister, hdsp->control_register);
4274 hdsp->midi[1].pending = 1;
4275 schedule = 1;
4276 } else {
4277 snd_hdsp_midi_input_read (&hdsp->midi[1]);
4278 }
4279 }
4280 if (hdsp->use_midi_tasklet && schedule)
Takashi Iwai1f041282008-12-18 12:17:55 +01004281 tasklet_schedule(&hdsp->midi_tasklet);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004282 return IRQ_HANDLED;
4283}
4284
Takashi Iwai55e957d2005-11-17 14:52:13 +01004285static snd_pcm_uframes_t snd_hdsp_hw_pointer(struct snd_pcm_substream *substream)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004286{
Takashi Iwai55e957d2005-11-17 14:52:13 +01004287 struct hdsp *hdsp = snd_pcm_substream_chip(substream);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004288 return hdsp_hw_pointer(hdsp);
4289}
4290
Takashi Iwai55e957d2005-11-17 14:52:13 +01004291static char *hdsp_channel_buffer_location(struct hdsp *hdsp,
Linus Torvalds1da177e2005-04-16 15:20:36 -07004292 int stream,
4293 int channel)
4294
4295{
4296 int mapped_channel;
4297
Takashi Iwaida3cec32008-08-08 17:12:14 +02004298 if (snd_BUG_ON(channel < 0 || channel >= hdsp->max_channels))
4299 return NULL;
Tim Blechmannf9ffc5d2009-02-20 19:38:16 +01004300
Takashi Iwaib0b981192005-10-20 18:29:58 +02004301 if ((mapped_channel = hdsp->channel_map[channel]) < 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004302 return NULL;
Tim Blechmannf9ffc5d2009-02-20 19:38:16 +01004303
Takashi Iwaib0b981192005-10-20 18:29:58 +02004304 if (stream == SNDRV_PCM_STREAM_CAPTURE)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004305 return hdsp->capture_buffer + (mapped_channel * HDSP_CHANNEL_BUFFER_BYTES);
Takashi Iwaib0b981192005-10-20 18:29:58 +02004306 else
Linus Torvalds1da177e2005-04-16 15:20:36 -07004307 return hdsp->playback_buffer + (mapped_channel * HDSP_CHANNEL_BUFFER_BYTES);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004308}
4309
Takashi Iwai55e957d2005-11-17 14:52:13 +01004310static int snd_hdsp_playback_copy(struct snd_pcm_substream *substream, int channel,
Linus Torvalds1da177e2005-04-16 15:20:36 -07004311 snd_pcm_uframes_t pos, void __user *src, snd_pcm_uframes_t count)
4312{
Takashi Iwai55e957d2005-11-17 14:52:13 +01004313 struct hdsp *hdsp = snd_pcm_substream_chip(substream);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004314 char *channel_buf;
4315
Takashi Iwaida3cec32008-08-08 17:12:14 +02004316 if (snd_BUG_ON(pos + count > HDSP_CHANNEL_BUFFER_BYTES / 4))
4317 return -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004318
4319 channel_buf = hdsp_channel_buffer_location (hdsp, substream->pstr->stream, channel);
Takashi Iwaida3cec32008-08-08 17:12:14 +02004320 if (snd_BUG_ON(!channel_buf))
4321 return -EIO;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004322 if (copy_from_user(channel_buf + pos * 4, src, count * 4))
4323 return -EFAULT;
4324 return count;
4325}
4326
Takashi Iwai55e957d2005-11-17 14:52:13 +01004327static int snd_hdsp_capture_copy(struct snd_pcm_substream *substream, int channel,
Linus Torvalds1da177e2005-04-16 15:20:36 -07004328 snd_pcm_uframes_t pos, void __user *dst, snd_pcm_uframes_t count)
4329{
Takashi Iwai55e957d2005-11-17 14:52:13 +01004330 struct hdsp *hdsp = snd_pcm_substream_chip(substream);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004331 char *channel_buf;
4332
Takashi Iwaida3cec32008-08-08 17:12:14 +02004333 if (snd_BUG_ON(pos + count > HDSP_CHANNEL_BUFFER_BYTES / 4))
4334 return -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004335
4336 channel_buf = hdsp_channel_buffer_location (hdsp, substream->pstr->stream, channel);
Takashi Iwaida3cec32008-08-08 17:12:14 +02004337 if (snd_BUG_ON(!channel_buf))
4338 return -EIO;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004339 if (copy_to_user(dst, channel_buf + pos * 4, count * 4))
4340 return -EFAULT;
4341 return count;
4342}
4343
Takashi Iwai55e957d2005-11-17 14:52:13 +01004344static int snd_hdsp_hw_silence(struct snd_pcm_substream *substream, int channel,
Linus Torvalds1da177e2005-04-16 15:20:36 -07004345 snd_pcm_uframes_t pos, snd_pcm_uframes_t count)
4346{
Takashi Iwai55e957d2005-11-17 14:52:13 +01004347 struct hdsp *hdsp = snd_pcm_substream_chip(substream);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004348 char *channel_buf;
4349
4350 channel_buf = hdsp_channel_buffer_location (hdsp, substream->pstr->stream, channel);
Takashi Iwaida3cec32008-08-08 17:12:14 +02004351 if (snd_BUG_ON(!channel_buf))
4352 return -EIO;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004353 memset(channel_buf + pos * 4, 0, count * 4);
4354 return count;
4355}
4356
Takashi Iwai55e957d2005-11-17 14:52:13 +01004357static int snd_hdsp_reset(struct snd_pcm_substream *substream)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004358{
Takashi Iwai55e957d2005-11-17 14:52:13 +01004359 struct snd_pcm_runtime *runtime = substream->runtime;
4360 struct hdsp *hdsp = snd_pcm_substream_chip(substream);
4361 struct snd_pcm_substream *other;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004362 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
4363 other = hdsp->capture_substream;
4364 else
4365 other = hdsp->playback_substream;
4366 if (hdsp->running)
4367 runtime->status->hw_ptr = hdsp_hw_pointer(hdsp);
4368 else
4369 runtime->status->hw_ptr = 0;
4370 if (other) {
Takashi Iwai55e957d2005-11-17 14:52:13 +01004371 struct snd_pcm_substream *s;
4372 struct snd_pcm_runtime *oruntime = other->runtime;
Takashi Iwaief991b92007-02-22 12:52:53 +01004373 snd_pcm_group_for_each_entry(s, substream) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004374 if (s == other) {
4375 oruntime->status->hw_ptr = runtime->status->hw_ptr;
4376 break;
4377 }
4378 }
4379 }
4380 return 0;
4381}
4382
Takashi Iwai55e957d2005-11-17 14:52:13 +01004383static int snd_hdsp_hw_params(struct snd_pcm_substream *substream,
4384 struct snd_pcm_hw_params *params)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004385{
Takashi Iwai55e957d2005-11-17 14:52:13 +01004386 struct hdsp *hdsp = snd_pcm_substream_chip(substream);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004387 int err;
4388 pid_t this_pid;
4389 pid_t other_pid;
4390
Takashi Iwaib0b981192005-10-20 18:29:58 +02004391 if (hdsp_check_for_iobox (hdsp))
Linus Torvalds1da177e2005-04-16 15:20:36 -07004392 return -EIO;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004393
Takashi Iwaib0b981192005-10-20 18:29:58 +02004394 if (hdsp_check_for_firmware(hdsp, 1))
Linus Torvalds1da177e2005-04-16 15:20:36 -07004395 return -EIO;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004396
4397 spin_lock_irq(&hdsp->lock);
4398
4399 if (substream->pstr->stream == SNDRV_PCM_STREAM_PLAYBACK) {
4400 hdsp->control_register &= ~(HDSP_SPDIFProfessional | HDSP_SPDIFNonAudio | HDSP_SPDIFEmphasis);
4401 hdsp_write(hdsp, HDSP_controlRegister, hdsp->control_register |= hdsp->creg_spdif_stream);
4402 this_pid = hdsp->playback_pid;
4403 other_pid = hdsp->capture_pid;
4404 } else {
4405 this_pid = hdsp->capture_pid;
4406 other_pid = hdsp->playback_pid;
4407 }
4408
4409 if ((other_pid > 0) && (this_pid != other_pid)) {
4410
4411 /* The other stream is open, and not by the same
4412 task as this one. Make sure that the parameters
4413 that matter are the same.
4414 */
4415
4416 if (params_rate(params) != hdsp->system_sample_rate) {
4417 spin_unlock_irq(&hdsp->lock);
4418 _snd_pcm_hw_param_setempty(params, SNDRV_PCM_HW_PARAM_RATE);
4419 return -EBUSY;
4420 }
4421
4422 if (params_period_size(params) != hdsp->period_bytes / 4) {
4423 spin_unlock_irq(&hdsp->lock);
4424 _snd_pcm_hw_param_setempty(params, SNDRV_PCM_HW_PARAM_PERIOD_SIZE);
4425 return -EBUSY;
4426 }
4427
4428 /* We're fine. */
4429
4430 spin_unlock_irq(&hdsp->lock);
4431 return 0;
4432
4433 } else {
4434 spin_unlock_irq(&hdsp->lock);
4435 }
4436
4437 /* how to make sure that the rate matches an externally-set one ?
4438 */
4439
4440 spin_lock_irq(&hdsp->lock);
Takashi Iwaie3ea4d82005-07-04 18:12:39 +02004441 if (! hdsp->clock_source_locked) {
4442 if ((err = hdsp_set_rate(hdsp, params_rate(params), 0)) < 0) {
4443 spin_unlock_irq(&hdsp->lock);
4444 _snd_pcm_hw_param_setempty(params, SNDRV_PCM_HW_PARAM_RATE);
4445 return err;
4446 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004447 }
Takashi Iwaie3ea4d82005-07-04 18:12:39 +02004448 spin_unlock_irq(&hdsp->lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004449
4450 if ((err = hdsp_set_interrupt_interval(hdsp, params_period_size(params))) < 0) {
4451 _snd_pcm_hw_param_setempty(params, SNDRV_PCM_HW_PARAM_PERIOD_SIZE);
4452 return err;
4453 }
4454
4455 return 0;
4456}
4457
Takashi Iwai55e957d2005-11-17 14:52:13 +01004458static int snd_hdsp_channel_info(struct snd_pcm_substream *substream,
4459 struct snd_pcm_channel_info *info)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004460{
Takashi Iwai55e957d2005-11-17 14:52:13 +01004461 struct hdsp *hdsp = snd_pcm_substream_chip(substream);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004462 int mapped_channel;
4463
Takashi Iwaida3cec32008-08-08 17:12:14 +02004464 if (snd_BUG_ON(info->channel >= hdsp->max_channels))
4465 return -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004466
Takashi Iwaib0b981192005-10-20 18:29:58 +02004467 if ((mapped_channel = hdsp->channel_map[info->channel]) < 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004468 return -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004469
4470 info->offset = mapped_channel * HDSP_CHANNEL_BUFFER_BYTES;
4471 info->first = 0;
4472 info->step = 32;
4473 return 0;
4474}
4475
Takashi Iwai55e957d2005-11-17 14:52:13 +01004476static int snd_hdsp_ioctl(struct snd_pcm_substream *substream,
Linus Torvalds1da177e2005-04-16 15:20:36 -07004477 unsigned int cmd, void *arg)
4478{
4479 switch (cmd) {
4480 case SNDRV_PCM_IOCTL1_RESET:
Linus Torvalds1da177e2005-04-16 15:20:36 -07004481 return snd_hdsp_reset(substream);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004482 case SNDRV_PCM_IOCTL1_CHANNEL_INFO:
Takashi Iwaib0b981192005-10-20 18:29:58 +02004483 return snd_hdsp_channel_info(substream, arg);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004484 default:
4485 break;
4486 }
4487
4488 return snd_pcm_lib_ioctl(substream, cmd, arg);
4489}
4490
Takashi Iwai55e957d2005-11-17 14:52:13 +01004491static int snd_hdsp_trigger(struct snd_pcm_substream *substream, int cmd)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004492{
Takashi Iwai55e957d2005-11-17 14:52:13 +01004493 struct hdsp *hdsp = snd_pcm_substream_chip(substream);
4494 struct snd_pcm_substream *other;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004495 int running;
Tim Blechmannf9ffc5d2009-02-20 19:38:16 +01004496
Takashi Iwaib0b981192005-10-20 18:29:58 +02004497 if (hdsp_check_for_iobox (hdsp))
Linus Torvalds1da177e2005-04-16 15:20:36 -07004498 return -EIO;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004499
Takashi Iwai311e70a2006-09-06 12:13:37 +02004500 if (hdsp_check_for_firmware(hdsp, 0)) /* no auto-loading in trigger */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004501 return -EIO;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004502
4503 spin_lock(&hdsp->lock);
4504 running = hdsp->running;
4505 switch (cmd) {
4506 case SNDRV_PCM_TRIGGER_START:
4507 running |= 1 << substream->stream;
4508 break;
4509 case SNDRV_PCM_TRIGGER_STOP:
4510 running &= ~(1 << substream->stream);
4511 break;
4512 default:
4513 snd_BUG();
4514 spin_unlock(&hdsp->lock);
4515 return -EINVAL;
4516 }
4517 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
4518 other = hdsp->capture_substream;
4519 else
4520 other = hdsp->playback_substream;
4521
4522 if (other) {
Takashi Iwai55e957d2005-11-17 14:52:13 +01004523 struct snd_pcm_substream *s;
Takashi Iwaief991b92007-02-22 12:52:53 +01004524 snd_pcm_group_for_each_entry(s, substream) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004525 if (s == other) {
4526 snd_pcm_trigger_done(s, substream);
4527 if (cmd == SNDRV_PCM_TRIGGER_START)
4528 running |= 1 << s->stream;
4529 else
4530 running &= ~(1 << s->stream);
4531 goto _ok;
4532 }
4533 }
4534 if (cmd == SNDRV_PCM_TRIGGER_START) {
4535 if (!(running & (1 << SNDRV_PCM_STREAM_PLAYBACK)) &&
4536 substream->stream == SNDRV_PCM_STREAM_CAPTURE)
4537 hdsp_silence_playback(hdsp);
4538 } else {
4539 if (running &&
4540 substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
4541 hdsp_silence_playback(hdsp);
4542 }
4543 } else {
4544 if (substream->stream == SNDRV_PCM_STREAM_CAPTURE)
4545 hdsp_silence_playback(hdsp);
4546 }
4547 _ok:
4548 snd_pcm_trigger_done(substream, substream);
4549 if (!hdsp->running && running)
4550 hdsp_start_audio(hdsp);
4551 else if (hdsp->running && !running)
4552 hdsp_stop_audio(hdsp);
4553 hdsp->running = running;
4554 spin_unlock(&hdsp->lock);
4555
4556 return 0;
4557}
4558
Takashi Iwai55e957d2005-11-17 14:52:13 +01004559static int snd_hdsp_prepare(struct snd_pcm_substream *substream)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004560{
Takashi Iwai55e957d2005-11-17 14:52:13 +01004561 struct hdsp *hdsp = snd_pcm_substream_chip(substream);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004562 int result = 0;
4563
Takashi Iwaib0b981192005-10-20 18:29:58 +02004564 if (hdsp_check_for_iobox (hdsp))
Linus Torvalds1da177e2005-04-16 15:20:36 -07004565 return -EIO;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004566
Takashi Iwaib0b981192005-10-20 18:29:58 +02004567 if (hdsp_check_for_firmware(hdsp, 1))
Linus Torvalds1da177e2005-04-16 15:20:36 -07004568 return -EIO;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004569
4570 spin_lock_irq(&hdsp->lock);
4571 if (!hdsp->running)
4572 hdsp_reset_hw_pointer(hdsp);
4573 spin_unlock_irq(&hdsp->lock);
4574 return result;
4575}
4576
Takashi Iwai55e957d2005-11-17 14:52:13 +01004577static struct snd_pcm_hardware snd_hdsp_playback_subinfo =
Linus Torvalds1da177e2005-04-16 15:20:36 -07004578{
4579 .info = (SNDRV_PCM_INFO_MMAP |
4580 SNDRV_PCM_INFO_MMAP_VALID |
4581 SNDRV_PCM_INFO_NONINTERLEAVED |
4582 SNDRV_PCM_INFO_SYNC_START |
4583 SNDRV_PCM_INFO_DOUBLE),
4584#ifdef SNDRV_BIG_ENDIAN
4585 .formats = SNDRV_PCM_FMTBIT_S32_BE,
4586#else
4587 .formats = SNDRV_PCM_FMTBIT_S32_LE,
4588#endif
4589 .rates = (SNDRV_PCM_RATE_32000 |
Tim Blechmannf9ffc5d2009-02-20 19:38:16 +01004590 SNDRV_PCM_RATE_44100 |
4591 SNDRV_PCM_RATE_48000 |
4592 SNDRV_PCM_RATE_64000 |
4593 SNDRV_PCM_RATE_88200 |
Linus Torvalds1da177e2005-04-16 15:20:36 -07004594 SNDRV_PCM_RATE_96000),
4595 .rate_min = 32000,
4596 .rate_max = 96000,
Florian Faber28b26e12010-12-01 12:14:47 +01004597 .channels_min = 6,
Linus Torvalds1da177e2005-04-16 15:20:36 -07004598 .channels_max = HDSP_MAX_CHANNELS,
4599 .buffer_bytes_max = HDSP_CHANNEL_BUFFER_BYTES * HDSP_MAX_CHANNELS,
4600 .period_bytes_min = (64 * 4) * 10,
4601 .period_bytes_max = (8192 * 4) * HDSP_MAX_CHANNELS,
4602 .periods_min = 2,
4603 .periods_max = 2,
4604 .fifo_size = 0
4605};
4606
Takashi Iwai55e957d2005-11-17 14:52:13 +01004607static struct snd_pcm_hardware snd_hdsp_capture_subinfo =
Linus Torvalds1da177e2005-04-16 15:20:36 -07004608{
4609 .info = (SNDRV_PCM_INFO_MMAP |
4610 SNDRV_PCM_INFO_MMAP_VALID |
4611 SNDRV_PCM_INFO_NONINTERLEAVED |
4612 SNDRV_PCM_INFO_SYNC_START),
4613#ifdef SNDRV_BIG_ENDIAN
4614 .formats = SNDRV_PCM_FMTBIT_S32_BE,
4615#else
4616 .formats = SNDRV_PCM_FMTBIT_S32_LE,
4617#endif
4618 .rates = (SNDRV_PCM_RATE_32000 |
Tim Blechmannf9ffc5d2009-02-20 19:38:16 +01004619 SNDRV_PCM_RATE_44100 |
4620 SNDRV_PCM_RATE_48000 |
4621 SNDRV_PCM_RATE_64000 |
4622 SNDRV_PCM_RATE_88200 |
Linus Torvalds1da177e2005-04-16 15:20:36 -07004623 SNDRV_PCM_RATE_96000),
4624 .rate_min = 32000,
4625 .rate_max = 96000,
Florian Faber28b26e12010-12-01 12:14:47 +01004626 .channels_min = 5,
Linus Torvalds1da177e2005-04-16 15:20:36 -07004627 .channels_max = HDSP_MAX_CHANNELS,
4628 .buffer_bytes_max = HDSP_CHANNEL_BUFFER_BYTES * HDSP_MAX_CHANNELS,
4629 .period_bytes_min = (64 * 4) * 10,
4630 .period_bytes_max = (8192 * 4) * HDSP_MAX_CHANNELS,
4631 .periods_min = 2,
4632 .periods_max = 2,
4633 .fifo_size = 0
4634};
4635
4636static unsigned int hdsp_period_sizes[] = { 64, 128, 256, 512, 1024, 2048, 4096, 8192 };
4637
Takashi Iwai55e957d2005-11-17 14:52:13 +01004638static struct snd_pcm_hw_constraint_list hdsp_hw_constraints_period_sizes = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004639 .count = ARRAY_SIZE(hdsp_period_sizes),
4640 .list = hdsp_period_sizes,
4641 .mask = 0
4642};
4643
4644static unsigned int hdsp_9632_sample_rates[] = { 32000, 44100, 48000, 64000, 88200, 96000, 128000, 176400, 192000 };
4645
Takashi Iwai55e957d2005-11-17 14:52:13 +01004646static struct snd_pcm_hw_constraint_list hdsp_hw_constraints_9632_sample_rates = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004647 .count = ARRAY_SIZE(hdsp_9632_sample_rates),
4648 .list = hdsp_9632_sample_rates,
4649 .mask = 0
4650};
4651
Takashi Iwai55e957d2005-11-17 14:52:13 +01004652static int snd_hdsp_hw_rule_in_channels(struct snd_pcm_hw_params *params,
4653 struct snd_pcm_hw_rule *rule)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004654{
Takashi Iwai55e957d2005-11-17 14:52:13 +01004655 struct hdsp *hdsp = rule->private;
4656 struct snd_interval *c = hw_param_interval(params, SNDRV_PCM_HW_PARAM_CHANNELS);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004657 if (hdsp->io_type == H9632) {
4658 unsigned int list[3];
4659 list[0] = hdsp->qs_in_channels;
4660 list[1] = hdsp->ds_in_channels;
4661 list[2] = hdsp->ss_in_channels;
4662 return snd_interval_list(c, 3, list, 0);
4663 } else {
4664 unsigned int list[2];
4665 list[0] = hdsp->ds_in_channels;
4666 list[1] = hdsp->ss_in_channels;
4667 return snd_interval_list(c, 2, list, 0);
4668 }
4669}
4670
Takashi Iwai55e957d2005-11-17 14:52:13 +01004671static int snd_hdsp_hw_rule_out_channels(struct snd_pcm_hw_params *params,
4672 struct snd_pcm_hw_rule *rule)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004673{
4674 unsigned int list[3];
Takashi Iwai55e957d2005-11-17 14:52:13 +01004675 struct hdsp *hdsp = rule->private;
4676 struct snd_interval *c = hw_param_interval(params, SNDRV_PCM_HW_PARAM_CHANNELS);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004677 if (hdsp->io_type == H9632) {
4678 list[0] = hdsp->qs_out_channels;
4679 list[1] = hdsp->ds_out_channels;
4680 list[2] = hdsp->ss_out_channels;
4681 return snd_interval_list(c, 3, list, 0);
4682 } else {
4683 list[0] = hdsp->ds_out_channels;
4684 list[1] = hdsp->ss_out_channels;
4685 }
4686 return snd_interval_list(c, 2, list, 0);
4687}
4688
Takashi Iwai55e957d2005-11-17 14:52:13 +01004689static int snd_hdsp_hw_rule_in_channels_rate(struct snd_pcm_hw_params *params,
4690 struct snd_pcm_hw_rule *rule)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004691{
Takashi Iwai55e957d2005-11-17 14:52:13 +01004692 struct hdsp *hdsp = rule->private;
4693 struct snd_interval *c = hw_param_interval(params, SNDRV_PCM_HW_PARAM_CHANNELS);
4694 struct snd_interval *r = hw_param_interval(params, SNDRV_PCM_HW_PARAM_RATE);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004695 if (r->min > 96000 && hdsp->io_type == H9632) {
Takashi Iwai55e957d2005-11-17 14:52:13 +01004696 struct snd_interval t = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004697 .min = hdsp->qs_in_channels,
4698 .max = hdsp->qs_in_channels,
4699 .integer = 1,
4700 };
Tim Blechmannf9ffc5d2009-02-20 19:38:16 +01004701 return snd_interval_refine(c, &t);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004702 } else if (r->min > 48000 && r->max <= 96000) {
Takashi Iwai55e957d2005-11-17 14:52:13 +01004703 struct snd_interval t = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004704 .min = hdsp->ds_in_channels,
4705 .max = hdsp->ds_in_channels,
4706 .integer = 1,
4707 };
4708 return snd_interval_refine(c, &t);
4709 } else if (r->max < 64000) {
Takashi Iwai55e957d2005-11-17 14:52:13 +01004710 struct snd_interval t = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004711 .min = hdsp->ss_in_channels,
4712 .max = hdsp->ss_in_channels,
4713 .integer = 1,
4714 };
4715 return snd_interval_refine(c, &t);
4716 }
4717 return 0;
4718}
4719
Takashi Iwai55e957d2005-11-17 14:52:13 +01004720static int snd_hdsp_hw_rule_out_channels_rate(struct snd_pcm_hw_params *params,
4721 struct snd_pcm_hw_rule *rule)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004722{
Takashi Iwai55e957d2005-11-17 14:52:13 +01004723 struct hdsp *hdsp = rule->private;
4724 struct snd_interval *c = hw_param_interval(params, SNDRV_PCM_HW_PARAM_CHANNELS);
4725 struct snd_interval *r = hw_param_interval(params, SNDRV_PCM_HW_PARAM_RATE);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004726 if (r->min > 96000 && hdsp->io_type == H9632) {
Takashi Iwai55e957d2005-11-17 14:52:13 +01004727 struct snd_interval t = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004728 .min = hdsp->qs_out_channels,
4729 .max = hdsp->qs_out_channels,
4730 .integer = 1,
4731 };
Tim Blechmannf9ffc5d2009-02-20 19:38:16 +01004732 return snd_interval_refine(c, &t);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004733 } else if (r->min > 48000 && r->max <= 96000) {
Takashi Iwai55e957d2005-11-17 14:52:13 +01004734 struct snd_interval t = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004735 .min = hdsp->ds_out_channels,
4736 .max = hdsp->ds_out_channels,
4737 .integer = 1,
4738 };
4739 return snd_interval_refine(c, &t);
4740 } else if (r->max < 64000) {
Takashi Iwai55e957d2005-11-17 14:52:13 +01004741 struct snd_interval t = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004742 .min = hdsp->ss_out_channels,
4743 .max = hdsp->ss_out_channels,
4744 .integer = 1,
4745 };
4746 return snd_interval_refine(c, &t);
4747 }
4748 return 0;
4749}
4750
Takashi Iwai55e957d2005-11-17 14:52:13 +01004751static int snd_hdsp_hw_rule_rate_out_channels(struct snd_pcm_hw_params *params,
4752 struct snd_pcm_hw_rule *rule)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004753{
Takashi Iwai55e957d2005-11-17 14:52:13 +01004754 struct hdsp *hdsp = rule->private;
4755 struct snd_interval *c = hw_param_interval(params, SNDRV_PCM_HW_PARAM_CHANNELS);
4756 struct snd_interval *r = hw_param_interval(params, SNDRV_PCM_HW_PARAM_RATE);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004757 if (c->min >= hdsp->ss_out_channels) {
Takashi Iwai55e957d2005-11-17 14:52:13 +01004758 struct snd_interval t = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004759 .min = 32000,
4760 .max = 48000,
4761 .integer = 1,
4762 };
4763 return snd_interval_refine(r, &t);
4764 } else if (c->max <= hdsp->qs_out_channels && hdsp->io_type == H9632) {
Takashi Iwai55e957d2005-11-17 14:52:13 +01004765 struct snd_interval t = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004766 .min = 128000,
4767 .max = 192000,
4768 .integer = 1,
4769 };
4770 return snd_interval_refine(r, &t);
4771 } else if (c->max <= hdsp->ds_out_channels) {
Takashi Iwai55e957d2005-11-17 14:52:13 +01004772 struct snd_interval t = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004773 .min = 64000,
4774 .max = 96000,
4775 .integer = 1,
4776 };
4777 return snd_interval_refine(r, &t);
4778 }
4779 return 0;
4780}
4781
Takashi Iwai55e957d2005-11-17 14:52:13 +01004782static int snd_hdsp_hw_rule_rate_in_channels(struct snd_pcm_hw_params *params,
4783 struct snd_pcm_hw_rule *rule)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004784{
Takashi Iwai55e957d2005-11-17 14:52:13 +01004785 struct hdsp *hdsp = rule->private;
4786 struct snd_interval *c = hw_param_interval(params, SNDRV_PCM_HW_PARAM_CHANNELS);
4787 struct snd_interval *r = hw_param_interval(params, SNDRV_PCM_HW_PARAM_RATE);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004788 if (c->min >= hdsp->ss_in_channels) {
Takashi Iwai55e957d2005-11-17 14:52:13 +01004789 struct snd_interval t = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004790 .min = 32000,
4791 .max = 48000,
4792 .integer = 1,
4793 };
4794 return snd_interval_refine(r, &t);
4795 } else if (c->max <= hdsp->qs_in_channels && hdsp->io_type == H9632) {
Takashi Iwai55e957d2005-11-17 14:52:13 +01004796 struct snd_interval t = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004797 .min = 128000,
4798 .max = 192000,
4799 .integer = 1,
4800 };
4801 return snd_interval_refine(r, &t);
4802 } else if (c->max <= hdsp->ds_in_channels) {
Takashi Iwai55e957d2005-11-17 14:52:13 +01004803 struct snd_interval t = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004804 .min = 64000,
4805 .max = 96000,
4806 .integer = 1,
4807 };
4808 return snd_interval_refine(r, &t);
4809 }
4810 return 0;
4811}
4812
Takashi Iwai55e957d2005-11-17 14:52:13 +01004813static int snd_hdsp_playback_open(struct snd_pcm_substream *substream)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004814{
Takashi Iwai55e957d2005-11-17 14:52:13 +01004815 struct hdsp *hdsp = snd_pcm_substream_chip(substream);
4816 struct snd_pcm_runtime *runtime = substream->runtime;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004817
Takashi Iwaib0b981192005-10-20 18:29:58 +02004818 if (hdsp_check_for_iobox (hdsp))
Linus Torvalds1da177e2005-04-16 15:20:36 -07004819 return -EIO;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004820
Takashi Iwaib0b981192005-10-20 18:29:58 +02004821 if (hdsp_check_for_firmware(hdsp, 1))
Linus Torvalds1da177e2005-04-16 15:20:36 -07004822 return -EIO;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004823
4824 spin_lock_irq(&hdsp->lock);
4825
4826 snd_pcm_set_sync(substream);
4827
4828 runtime->hw = snd_hdsp_playback_subinfo;
4829 runtime->dma_area = hdsp->playback_buffer;
4830 runtime->dma_bytes = HDSP_DMA_AREA_BYTES;
4831
4832 hdsp->playback_pid = current->pid;
4833 hdsp->playback_substream = substream;
4834
4835 spin_unlock_irq(&hdsp->lock);
4836
4837 snd_pcm_hw_constraint_msbits(runtime, 0, 32, 24);
4838 snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_PERIOD_SIZE, &hdsp_hw_constraints_period_sizes);
Takashi Iwaie3ea4d82005-07-04 18:12:39 +02004839 if (hdsp->clock_source_locked) {
4840 runtime->hw.rate_min = runtime->hw.rate_max = hdsp->system_sample_rate;
4841 } else if (hdsp->io_type == H9632) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004842 runtime->hw.rate_max = 192000;
4843 runtime->hw.rates = SNDRV_PCM_RATE_KNOT;
4844 snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_RATE, &hdsp_hw_constraints_9632_sample_rates);
4845 }
Takashi Iwaie3ea4d82005-07-04 18:12:39 +02004846 if (hdsp->io_type == H9632) {
4847 runtime->hw.channels_min = hdsp->qs_out_channels;
4848 runtime->hw.channels_max = hdsp->ss_out_channels;
Tim Blechmannf9ffc5d2009-02-20 19:38:16 +01004849 }
4850
Linus Torvalds1da177e2005-04-16 15:20:36 -07004851 snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_CHANNELS,
4852 snd_hdsp_hw_rule_out_channels, hdsp,
4853 SNDRV_PCM_HW_PARAM_CHANNELS, -1);
4854 snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_CHANNELS,
4855 snd_hdsp_hw_rule_out_channels_rate, hdsp,
4856 SNDRV_PCM_HW_PARAM_RATE, -1);
4857 snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_RATE,
4858 snd_hdsp_hw_rule_rate_out_channels, hdsp,
4859 SNDRV_PCM_HW_PARAM_CHANNELS, -1);
4860
Florian Faber28b26e12010-12-01 12:14:47 +01004861 if (RPM != hdsp->io_type) {
4862 hdsp->creg_spdif_stream = hdsp->creg_spdif;
4863 hdsp->spdif_ctl->vd[0].access &= ~SNDRV_CTL_ELEM_ACCESS_INACTIVE;
4864 snd_ctl_notify(hdsp->card, SNDRV_CTL_EVENT_MASK_VALUE |
4865 SNDRV_CTL_EVENT_MASK_INFO, &hdsp->spdif_ctl->id);
4866 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004867 return 0;
4868}
4869
Takashi Iwai55e957d2005-11-17 14:52:13 +01004870static int snd_hdsp_playback_release(struct snd_pcm_substream *substream)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004871{
Takashi Iwai55e957d2005-11-17 14:52:13 +01004872 struct hdsp *hdsp = snd_pcm_substream_chip(substream);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004873
4874 spin_lock_irq(&hdsp->lock);
4875
4876 hdsp->playback_pid = -1;
4877 hdsp->playback_substream = NULL;
4878
4879 spin_unlock_irq(&hdsp->lock);
4880
Florian Faber28b26e12010-12-01 12:14:47 +01004881 if (RPM != hdsp->io_type) {
4882 hdsp->spdif_ctl->vd[0].access |= SNDRV_CTL_ELEM_ACCESS_INACTIVE;
4883 snd_ctl_notify(hdsp->card, SNDRV_CTL_EVENT_MASK_VALUE |
4884 SNDRV_CTL_EVENT_MASK_INFO, &hdsp->spdif_ctl->id);
4885 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004886 return 0;
4887}
4888
4889
Takashi Iwai55e957d2005-11-17 14:52:13 +01004890static int snd_hdsp_capture_open(struct snd_pcm_substream *substream)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004891{
Takashi Iwai55e957d2005-11-17 14:52:13 +01004892 struct hdsp *hdsp = snd_pcm_substream_chip(substream);
4893 struct snd_pcm_runtime *runtime = substream->runtime;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004894
Takashi Iwaib0b981192005-10-20 18:29:58 +02004895 if (hdsp_check_for_iobox (hdsp))
Linus Torvalds1da177e2005-04-16 15:20:36 -07004896 return -EIO;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004897
Takashi Iwaib0b981192005-10-20 18:29:58 +02004898 if (hdsp_check_for_firmware(hdsp, 1))
Linus Torvalds1da177e2005-04-16 15:20:36 -07004899 return -EIO;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004900
4901 spin_lock_irq(&hdsp->lock);
4902
4903 snd_pcm_set_sync(substream);
4904
4905 runtime->hw = snd_hdsp_capture_subinfo;
4906 runtime->dma_area = hdsp->capture_buffer;
4907 runtime->dma_bytes = HDSP_DMA_AREA_BYTES;
4908
4909 hdsp->capture_pid = current->pid;
4910 hdsp->capture_substream = substream;
4911
4912 spin_unlock_irq(&hdsp->lock);
4913
4914 snd_pcm_hw_constraint_msbits(runtime, 0, 32, 24);
4915 snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_PERIOD_SIZE, &hdsp_hw_constraints_period_sizes);
4916 if (hdsp->io_type == H9632) {
4917 runtime->hw.channels_min = hdsp->qs_in_channels;
4918 runtime->hw.channels_max = hdsp->ss_in_channels;
4919 runtime->hw.rate_max = 192000;
4920 runtime->hw.rates = SNDRV_PCM_RATE_KNOT;
4921 snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_RATE, &hdsp_hw_constraints_9632_sample_rates);
4922 }
4923 snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_CHANNELS,
4924 snd_hdsp_hw_rule_in_channels, hdsp,
4925 SNDRV_PCM_HW_PARAM_CHANNELS, -1);
4926 snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_CHANNELS,
4927 snd_hdsp_hw_rule_in_channels_rate, hdsp,
4928 SNDRV_PCM_HW_PARAM_RATE, -1);
4929 snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_RATE,
4930 snd_hdsp_hw_rule_rate_in_channels, hdsp,
4931 SNDRV_PCM_HW_PARAM_CHANNELS, -1);
4932 return 0;
4933}
4934
Takashi Iwai55e957d2005-11-17 14:52:13 +01004935static int snd_hdsp_capture_release(struct snd_pcm_substream *substream)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004936{
Takashi Iwai55e957d2005-11-17 14:52:13 +01004937 struct hdsp *hdsp = snd_pcm_substream_chip(substream);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004938
4939 spin_lock_irq(&hdsp->lock);
4940
4941 hdsp->capture_pid = -1;
4942 hdsp->capture_substream = NULL;
4943
4944 spin_unlock_irq(&hdsp->lock);
4945 return 0;
4946}
4947
Linus Torvalds1da177e2005-04-16 15:20:36 -07004948/* helper functions for copying meter values */
4949static inline int copy_u32_le(void __user *dest, void __iomem *src)
4950{
4951 u32 val = readl(src);
4952 return copy_to_user(dest, &val, 4);
4953}
4954
4955static inline int copy_u64_le(void __user *dest, void __iomem *src_low, void __iomem *src_high)
4956{
4957 u32 rms_low, rms_high;
4958 u64 rms;
4959 rms_low = readl(src_low);
4960 rms_high = readl(src_high);
4961 rms = ((u64)rms_high << 32) | rms_low;
4962 return copy_to_user(dest, &rms, 8);
4963}
4964
4965static inline int copy_u48_le(void __user *dest, void __iomem *src_low, void __iomem *src_high)
4966{
4967 u32 rms_low, rms_high;
4968 u64 rms;
4969 rms_low = readl(src_low) & 0xffffff00;
4970 rms_high = readl(src_high) & 0xffffff00;
4971 rms = ((u64)rms_high << 32) | rms_low;
4972 return copy_to_user(dest, &rms, 8);
4973}
4974
Takashi Iwai55e957d2005-11-17 14:52:13 +01004975static int hdsp_9652_get_peak(struct hdsp *hdsp, struct hdsp_peak_rms __user *peak_rms)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004976{
4977 int doublespeed = 0;
4978 int i, j, channels, ofs;
4979
4980 if (hdsp_read (hdsp, HDSP_statusRegister) & HDSP_DoubleSpeedStatus)
4981 doublespeed = 1;
4982 channels = doublespeed ? 14 : 26;
4983 for (i = 0, j = 0; i < 26; ++i) {
4984 if (doublespeed && (i & 4))
4985 continue;
4986 ofs = HDSP_9652_peakBase - j * 4;
4987 if (copy_u32_le(&peak_rms->input_peaks[i], hdsp->iobase + ofs))
4988 return -EFAULT;
4989 ofs -= channels * 4;
4990 if (copy_u32_le(&peak_rms->playback_peaks[i], hdsp->iobase + ofs))
4991 return -EFAULT;
4992 ofs -= channels * 4;
4993 if (copy_u32_le(&peak_rms->output_peaks[i], hdsp->iobase + ofs))
4994 return -EFAULT;
4995 ofs = HDSP_9652_rmsBase + j * 8;
4996 if (copy_u48_le(&peak_rms->input_rms[i], hdsp->iobase + ofs,
4997 hdsp->iobase + ofs + 4))
4998 return -EFAULT;
4999 ofs += channels * 8;
5000 if (copy_u48_le(&peak_rms->playback_rms[i], hdsp->iobase + ofs,
5001 hdsp->iobase + ofs + 4))
5002 return -EFAULT;
5003 ofs += channels * 8;
5004 if (copy_u48_le(&peak_rms->output_rms[i], hdsp->iobase + ofs,
5005 hdsp->iobase + ofs + 4))
5006 return -EFAULT;
5007 j++;
5008 }
5009 return 0;
5010}
5011
Takashi Iwai55e957d2005-11-17 14:52:13 +01005012static int hdsp_9632_get_peak(struct hdsp *hdsp, struct hdsp_peak_rms __user *peak_rms)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005013{
5014 int i, j;
Takashi Iwai55e957d2005-11-17 14:52:13 +01005015 struct hdsp_9632_meters __iomem *m;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005016 int doublespeed = 0;
5017
5018 if (hdsp_read (hdsp, HDSP_statusRegister) & HDSP_DoubleSpeedStatus)
5019 doublespeed = 1;
Takashi Iwai55e957d2005-11-17 14:52:13 +01005020 m = (struct hdsp_9632_meters __iomem *)(hdsp->iobase+HDSP_9632_metersBase);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005021 for (i = 0, j = 0; i < 16; ++i, ++j) {
5022 if (copy_u32_le(&peak_rms->input_peaks[i], &m->input_peak[j]))
5023 return -EFAULT;
5024 if (copy_u32_le(&peak_rms->playback_peaks[i], &m->playback_peak[j]))
5025 return -EFAULT;
5026 if (copy_u32_le(&peak_rms->output_peaks[i], &m->output_peak[j]))
5027 return -EFAULT;
5028 if (copy_u64_le(&peak_rms->input_rms[i], &m->input_rms_low[j],
5029 &m->input_rms_high[j]))
5030 return -EFAULT;
5031 if (copy_u64_le(&peak_rms->playback_rms[i], &m->playback_rms_low[j],
5032 &m->playback_rms_high[j]))
5033 return -EFAULT;
5034 if (copy_u64_le(&peak_rms->output_rms[i], &m->output_rms_low[j],
5035 &m->output_rms_high[j]))
5036 return -EFAULT;
5037 if (doublespeed && i == 3) i += 4;
5038 }
5039 return 0;
5040}
5041
Takashi Iwai55e957d2005-11-17 14:52:13 +01005042static int hdsp_get_peak(struct hdsp *hdsp, struct hdsp_peak_rms __user *peak_rms)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005043{
5044 int i;
5045
5046 for (i = 0; i < 26; i++) {
5047 if (copy_u32_le(&peak_rms->playback_peaks[i],
5048 hdsp->iobase + HDSP_playbackPeakLevel + i * 4))
5049 return -EFAULT;
5050 if (copy_u32_le(&peak_rms->input_peaks[i],
5051 hdsp->iobase + HDSP_inputPeakLevel + i * 4))
5052 return -EFAULT;
5053 }
5054 for (i = 0; i < 28; i++) {
5055 if (copy_u32_le(&peak_rms->output_peaks[i],
5056 hdsp->iobase + HDSP_outputPeakLevel + i * 4))
5057 return -EFAULT;
5058 }
5059 for (i = 0; i < 26; ++i) {
5060 if (copy_u64_le(&peak_rms->playback_rms[i],
5061 hdsp->iobase + HDSP_playbackRmsLevel + i * 8 + 4,
5062 hdsp->iobase + HDSP_playbackRmsLevel + i * 8))
5063 return -EFAULT;
Tim Blechmannf9ffc5d2009-02-20 19:38:16 +01005064 if (copy_u64_le(&peak_rms->input_rms[i],
Linus Torvalds1da177e2005-04-16 15:20:36 -07005065 hdsp->iobase + HDSP_inputRmsLevel + i * 8 + 4,
5066 hdsp->iobase + HDSP_inputRmsLevel + i * 8))
5067 return -EFAULT;
5068 }
5069 return 0;
5070}
5071
Takashi Iwai55e957d2005-11-17 14:52:13 +01005072static int snd_hdsp_hwdep_ioctl(struct snd_hwdep *hw, struct file *file, unsigned int cmd, unsigned long arg)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005073{
Joe Perches9fe856e2010-09-04 18:52:54 -07005074 struct hdsp *hdsp = hw->private_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005075 void __user *argp = (void __user *)arg;
Tim Blechmann3ae7e2e2008-11-08 14:42:18 +01005076 int err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005077
5078 switch (cmd) {
5079 case SNDRV_HDSP_IOCTL_GET_PEAK_RMS: {
Takashi Iwai55e957d2005-11-17 14:52:13 +01005080 struct hdsp_peak_rms __user *peak_rms = (struct hdsp_peak_rms __user *)arg;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005081
Tim Blechmann3ae7e2e2008-11-08 14:42:18 +01005082 err = hdsp_check_for_iobox(hdsp);
5083 if (err < 0)
5084 return err;
5085
5086 err = hdsp_check_for_firmware(hdsp, 1);
5087 if (err < 0)
5088 return err;
5089
Linus Torvalds1da177e2005-04-16 15:20:36 -07005090 if (!(hdsp->state & HDSP_FirmwareLoaded)) {
5091 snd_printk(KERN_ERR "Hammerfall-DSP: firmware needs to be uploaded to the card.\n");
5092 return -EINVAL;
5093 }
5094
5095 switch (hdsp->io_type) {
5096 case H9652:
5097 return hdsp_9652_get_peak(hdsp, peak_rms);
5098 case H9632:
5099 return hdsp_9632_get_peak(hdsp, peak_rms);
5100 default:
5101 return hdsp_get_peak(hdsp, peak_rms);
5102 }
5103 }
5104 case SNDRV_HDSP_IOCTL_GET_CONFIG_INFO: {
Takashi Iwai55e957d2005-11-17 14:52:13 +01005105 struct hdsp_config_info info;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005106 unsigned long flags;
5107 int i;
Tim Blechmannf9ffc5d2009-02-20 19:38:16 +01005108
Tim Blechmann3ae7e2e2008-11-08 14:42:18 +01005109 err = hdsp_check_for_iobox(hdsp);
5110 if (err < 0)
5111 return err;
5112
5113 err = hdsp_check_for_firmware(hdsp, 1);
5114 if (err < 0)
5115 return err;
5116
Dan Rosenberge68d3b32010-09-25 11:07:27 -04005117 memset(&info, 0, sizeof(info));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005118 spin_lock_irqsave(&hdsp->lock, flags);
5119 info.pref_sync_ref = (unsigned char)hdsp_pref_sync_ref(hdsp);
5120 info.wordclock_sync_check = (unsigned char)hdsp_wc_sync_check(hdsp);
Takashi Iwaib0b981192005-10-20 18:29:58 +02005121 if (hdsp->io_type != H9632)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005122 info.adatsync_sync_check = (unsigned char)hdsp_adatsync_sync_check(hdsp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005123 info.spdif_sync_check = (unsigned char)hdsp_spdif_sync_check(hdsp);
Florian Faber28b26e12010-12-01 12:14:47 +01005124 for (i = 0; i < ((hdsp->io_type != Multiface && hdsp->io_type != RPM && hdsp->io_type != H9632) ? 3 : 1); ++i)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005125 info.adat_sync_check[i] = (unsigned char)hdsp_adat_sync_check(hdsp, i);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005126 info.spdif_in = (unsigned char)hdsp_spdif_in(hdsp);
5127 info.spdif_out = (unsigned char)hdsp_spdif_out(hdsp);
5128 info.spdif_professional = (unsigned char)hdsp_spdif_professional(hdsp);
5129 info.spdif_emphasis = (unsigned char)hdsp_spdif_emphasis(hdsp);
5130 info.spdif_nonaudio = (unsigned char)hdsp_spdif_nonaudio(hdsp);
5131 info.spdif_sample_rate = hdsp_spdif_sample_rate(hdsp);
5132 info.system_sample_rate = hdsp->system_sample_rate;
5133 info.autosync_sample_rate = hdsp_external_sample_rate(hdsp);
5134 info.system_clock_mode = (unsigned char)hdsp_system_clock_mode(hdsp);
5135 info.clock_source = (unsigned char)hdsp_clock_source(hdsp);
5136 info.autosync_ref = (unsigned char)hdsp_autosync_ref(hdsp);
5137 info.line_out = (unsigned char)hdsp_line_out(hdsp);
5138 if (hdsp->io_type == H9632) {
5139 info.da_gain = (unsigned char)hdsp_da_gain(hdsp);
5140 info.ad_gain = (unsigned char)hdsp_ad_gain(hdsp);
5141 info.phone_gain = (unsigned char)hdsp_phone_gain(hdsp);
5142 info.xlr_breakout_cable = (unsigned char)hdsp_xlr_breakout_cable(hdsp);
Tim Blechmannf9ffc5d2009-02-20 19:38:16 +01005143
Florian Faber28b26e12010-12-01 12:14:47 +01005144 } else if (hdsp->io_type == RPM) {
5145 info.da_gain = (unsigned char) hdsp_rpm_input12(hdsp);
5146 info.ad_gain = (unsigned char) hdsp_rpm_input34(hdsp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005147 }
Takashi Iwaib0b981192005-10-20 18:29:58 +02005148 if (hdsp->io_type == H9632 || hdsp->io_type == H9652)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005149 info.analog_extension_board = (unsigned char)hdsp_aeb(hdsp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005150 spin_unlock_irqrestore(&hdsp->lock, flags);
5151 if (copy_to_user(argp, &info, sizeof(info)))
5152 return -EFAULT;
5153 break;
5154 }
5155 case SNDRV_HDSP_IOCTL_GET_9632_AEB: {
Takashi Iwai55e957d2005-11-17 14:52:13 +01005156 struct hdsp_9632_aeb h9632_aeb;
Tim Blechmannf9ffc5d2009-02-20 19:38:16 +01005157
Linus Torvalds1da177e2005-04-16 15:20:36 -07005158 if (hdsp->io_type != H9632) return -EINVAL;
5159 h9632_aeb.aebi = hdsp->ss_in_channels - H9632_SS_CHANNELS;
5160 h9632_aeb.aebo = hdsp->ss_out_channels - H9632_SS_CHANNELS;
5161 if (copy_to_user(argp, &h9632_aeb, sizeof(h9632_aeb)))
5162 return -EFAULT;
5163 break;
5164 }
5165 case SNDRV_HDSP_IOCTL_GET_VERSION: {
Takashi Iwai55e957d2005-11-17 14:52:13 +01005166 struct hdsp_version hdsp_version;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005167 int err;
Tim Blechmannf9ffc5d2009-02-20 19:38:16 +01005168
Linus Torvalds1da177e2005-04-16 15:20:36 -07005169 if (hdsp->io_type == H9652 || hdsp->io_type == H9632) return -EINVAL;
5170 if (hdsp->io_type == Undefined) {
Takashi Iwaib0b981192005-10-20 18:29:58 +02005171 if ((err = hdsp_get_iobox_version(hdsp)) < 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005172 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005173 }
5174 hdsp_version.io_type = hdsp->io_type;
5175 hdsp_version.firmware_rev = hdsp->firmware_rev;
Takashi Iwaib0b981192005-10-20 18:29:58 +02005176 if ((err = copy_to_user(argp, &hdsp_version, sizeof(hdsp_version))))
Linus Torvalds1da177e2005-04-16 15:20:36 -07005177 return -EFAULT;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005178 break;
5179 }
5180 case SNDRV_HDSP_IOCTL_UPLOAD_FIRMWARE: {
Takashi Iwai55e957d2005-11-17 14:52:13 +01005181 struct hdsp_firmware __user *firmware;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005182 u32 __user *firmware_data;
5183 int err;
Tim Blechmannf9ffc5d2009-02-20 19:38:16 +01005184
Linus Torvalds1da177e2005-04-16 15:20:36 -07005185 if (hdsp->io_type == H9652 || hdsp->io_type == H9632) return -EINVAL;
5186 /* SNDRV_HDSP_IOCTL_GET_VERSION must have been called */
5187 if (hdsp->io_type == Undefined) return -EINVAL;
5188
5189 if (hdsp->state & (HDSP_FirmwareCached | HDSP_FirmwareLoaded))
5190 return -EBUSY;
5191
Takashi Iwaib0b981192005-10-20 18:29:58 +02005192 snd_printk(KERN_INFO "Hammerfall-DSP: initializing firmware upload\n");
Takashi Iwai55e957d2005-11-17 14:52:13 +01005193 firmware = (struct hdsp_firmware __user *)argp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005194
Takashi Iwaib0b981192005-10-20 18:29:58 +02005195 if (get_user(firmware_data, &firmware->firmware_data))
Linus Torvalds1da177e2005-04-16 15:20:36 -07005196 return -EFAULT;
Tim Blechmannf9ffc5d2009-02-20 19:38:16 +01005197
Takashi Iwaib0b981192005-10-20 18:29:58 +02005198 if (hdsp_check_for_iobox (hdsp))
Linus Torvalds1da177e2005-04-16 15:20:36 -07005199 return -EIO;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005200
Takashi Iwai90caaef2012-11-22 16:55:11 +01005201 if (!hdsp->fw_uploaded) {
5202 hdsp->fw_uploaded = vmalloc(HDSP_FIRMWARE_SIZE);
5203 if (!hdsp->fw_uploaded)
5204 return -ENOMEM;
5205 }
5206
5207 if (copy_from_user(hdsp->fw_uploaded, firmware_data,
5208 HDSP_FIRMWARE_SIZE)) {
5209 vfree(hdsp->fw_uploaded);
5210 hdsp->fw_uploaded = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005211 return -EFAULT;
Takashi Iwai90caaef2012-11-22 16:55:11 +01005212 }
Tim Blechmannf9ffc5d2009-02-20 19:38:16 +01005213
Linus Torvalds1da177e2005-04-16 15:20:36 -07005214 hdsp->state |= HDSP_FirmwareCached;
5215
Takashi Iwaib0b981192005-10-20 18:29:58 +02005216 if ((err = snd_hdsp_load_firmware_from_cache(hdsp)) < 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005217 return err;
Tim Blechmannf9ffc5d2009-02-20 19:38:16 +01005218
Linus Torvalds1da177e2005-04-16 15:20:36 -07005219 if (!(hdsp->state & HDSP_InitializationComplete)) {
Takashi Iwaib0b981192005-10-20 18:29:58 +02005220 if ((err = snd_hdsp_enable_io(hdsp)) < 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005221 return err;
Tim Blechmannf9ffc5d2009-02-20 19:38:16 +01005222
5223 snd_hdsp_initialize_channels(hdsp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005224 snd_hdsp_initialize_midi_flush(hdsp);
Tim Blechmannf9ffc5d2009-02-20 19:38:16 +01005225
Linus Torvalds1da177e2005-04-16 15:20:36 -07005226 if ((err = snd_hdsp_create_alsa_devices(hdsp->card, hdsp)) < 0) {
Takashi Iwaib0b981192005-10-20 18:29:58 +02005227 snd_printk(KERN_ERR "Hammerfall-DSP: error creating alsa devices\n");
5228 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005229 }
5230 }
5231 break;
5232 }
5233 case SNDRV_HDSP_IOCTL_GET_MIXER: {
Takashi Iwai55e957d2005-11-17 14:52:13 +01005234 struct hdsp_mixer __user *mixer = (struct hdsp_mixer __user *)argp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005235 if (copy_to_user(mixer->matrix, hdsp->mixer_matrix, sizeof(unsigned short)*HDSP_MATRIX_MIXER_SIZE))
5236 return -EFAULT;
5237 break;
5238 }
5239 default:
5240 return -EINVAL;
5241 }
5242 return 0;
5243}
5244
Takashi Iwai55e957d2005-11-17 14:52:13 +01005245static struct snd_pcm_ops snd_hdsp_playback_ops = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005246 .open = snd_hdsp_playback_open,
5247 .close = snd_hdsp_playback_release,
5248 .ioctl = snd_hdsp_ioctl,
5249 .hw_params = snd_hdsp_hw_params,
5250 .prepare = snd_hdsp_prepare,
5251 .trigger = snd_hdsp_trigger,
5252 .pointer = snd_hdsp_hw_pointer,
5253 .copy = snd_hdsp_playback_copy,
5254 .silence = snd_hdsp_hw_silence,
5255};
5256
Takashi Iwai55e957d2005-11-17 14:52:13 +01005257static struct snd_pcm_ops snd_hdsp_capture_ops = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005258 .open = snd_hdsp_capture_open,
5259 .close = snd_hdsp_capture_release,
5260 .ioctl = snd_hdsp_ioctl,
5261 .hw_params = snd_hdsp_hw_params,
5262 .prepare = snd_hdsp_prepare,
5263 .trigger = snd_hdsp_trigger,
5264 .pointer = snd_hdsp_hw_pointer,
5265 .copy = snd_hdsp_capture_copy,
5266};
5267
Takashi Iwai92eed662008-02-22 18:35:56 +01005268static int snd_hdsp_create_hwdep(struct snd_card *card, struct hdsp *hdsp)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005269{
Takashi Iwai55e957d2005-11-17 14:52:13 +01005270 struct snd_hwdep *hw;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005271 int err;
Tim Blechmannf9ffc5d2009-02-20 19:38:16 +01005272
Linus Torvalds1da177e2005-04-16 15:20:36 -07005273 if ((err = snd_hwdep_new(card, "HDSP hwdep", 0, &hw)) < 0)
5274 return err;
Tim Blechmannf9ffc5d2009-02-20 19:38:16 +01005275
Linus Torvalds1da177e2005-04-16 15:20:36 -07005276 hdsp->hwdep = hw;
5277 hw->private_data = hdsp;
5278 strcpy(hw->name, "HDSP hwdep interface");
5279
Linus Torvalds1da177e2005-04-16 15:20:36 -07005280 hw->ops.ioctl = snd_hdsp_hwdep_ioctl;
Andre Schramm42eb9232012-05-07 18:52:51 +02005281 hw->ops.ioctl_compat = snd_hdsp_hwdep_ioctl;
Tim Blechmannf9ffc5d2009-02-20 19:38:16 +01005282
Linus Torvalds1da177e2005-04-16 15:20:36 -07005283 return 0;
5284}
5285
Takashi Iwai55e957d2005-11-17 14:52:13 +01005286static int snd_hdsp_create_pcm(struct snd_card *card, struct hdsp *hdsp)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005287{
Takashi Iwai55e957d2005-11-17 14:52:13 +01005288 struct snd_pcm *pcm;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005289 int err;
5290
5291 if ((err = snd_pcm_new(card, hdsp->card_name, 0, 1, 1, &pcm)) < 0)
5292 return err;
5293
5294 hdsp->pcm = pcm;
5295 pcm->private_data = hdsp;
5296 strcpy(pcm->name, hdsp->card_name);
5297
5298 snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &snd_hdsp_playback_ops);
5299 snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &snd_hdsp_capture_ops);
5300
5301 pcm->info_flags = SNDRV_PCM_INFO_JOINT_DUPLEX;
5302
5303 return 0;
5304}
5305
Takashi Iwai55e957d2005-11-17 14:52:13 +01005306static void snd_hdsp_9652_enable_mixer (struct hdsp *hdsp)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005307{
5308 hdsp->control2_register |= HDSP_9652_ENABLE_MIXER;
5309 hdsp_write (hdsp, HDSP_control2Reg, hdsp->control2_register);
5310}
5311
Takashi Iwai55e957d2005-11-17 14:52:13 +01005312static int snd_hdsp_enable_io (struct hdsp *hdsp)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005313{
5314 int i;
Tim Blechmannf9ffc5d2009-02-20 19:38:16 +01005315
Linus Torvalds1da177e2005-04-16 15:20:36 -07005316 if (hdsp_fifo_wait (hdsp, 0, 100)) {
Takashi Iwaib0b981192005-10-20 18:29:58 +02005317 snd_printk(KERN_ERR "Hammerfall-DSP: enable_io fifo_wait failed\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07005318 return -EIO;
5319 }
Tim Blechmannf9ffc5d2009-02-20 19:38:16 +01005320
Linus Torvalds1da177e2005-04-16 15:20:36 -07005321 for (i = 0; i < hdsp->max_channels; ++i) {
5322 hdsp_write (hdsp, HDSP_inputEnable + (4 * i), 1);
5323 hdsp_write (hdsp, HDSP_outputEnable + (4 * i), 1);
5324 }
Tim Blechmannf9ffc5d2009-02-20 19:38:16 +01005325
Linus Torvalds1da177e2005-04-16 15:20:36 -07005326 return 0;
5327}
5328
Takashi Iwai55e957d2005-11-17 14:52:13 +01005329static void snd_hdsp_initialize_channels(struct hdsp *hdsp)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005330{
5331 int status, aebi_channels, aebo_channels;
Tim Blechmannf9ffc5d2009-02-20 19:38:16 +01005332
Linus Torvalds1da177e2005-04-16 15:20:36 -07005333 switch (hdsp->io_type) {
5334 case Digiface:
5335 hdsp->card_name = "RME Hammerfall DSP + Digiface";
5336 hdsp->ss_in_channels = hdsp->ss_out_channels = DIGIFACE_SS_CHANNELS;
5337 hdsp->ds_in_channels = hdsp->ds_out_channels = DIGIFACE_DS_CHANNELS;
5338 break;
5339
5340 case H9652:
5341 hdsp->card_name = "RME Hammerfall HDSP 9652";
5342 hdsp->ss_in_channels = hdsp->ss_out_channels = H9652_SS_CHANNELS;
5343 hdsp->ds_in_channels = hdsp->ds_out_channels = H9652_DS_CHANNELS;
5344 break;
Tim Blechmannf9ffc5d2009-02-20 19:38:16 +01005345
Linus Torvalds1da177e2005-04-16 15:20:36 -07005346 case H9632:
5347 status = hdsp_read(hdsp, HDSP_statusRegister);
5348 /* HDSP_AEBx bits are low when AEB are connected */
5349 aebi_channels = (status & HDSP_AEBI) ? 0 : 4;
5350 aebo_channels = (status & HDSP_AEBO) ? 0 : 4;
5351 hdsp->card_name = "RME Hammerfall HDSP 9632";
5352 hdsp->ss_in_channels = H9632_SS_CHANNELS+aebi_channels;
5353 hdsp->ds_in_channels = H9632_DS_CHANNELS+aebi_channels;
5354 hdsp->qs_in_channels = H9632_QS_CHANNELS+aebi_channels;
5355 hdsp->ss_out_channels = H9632_SS_CHANNELS+aebo_channels;
5356 hdsp->ds_out_channels = H9632_DS_CHANNELS+aebo_channels;
5357 hdsp->qs_out_channels = H9632_QS_CHANNELS+aebo_channels;
5358 break;
5359
5360 case Multiface:
5361 hdsp->card_name = "RME Hammerfall DSP + Multiface";
5362 hdsp->ss_in_channels = hdsp->ss_out_channels = MULTIFACE_SS_CHANNELS;
5363 hdsp->ds_in_channels = hdsp->ds_out_channels = MULTIFACE_DS_CHANNELS;
5364 break;
Tim Blechmannf9ffc5d2009-02-20 19:38:16 +01005365
Florian Faber28b26e12010-12-01 12:14:47 +01005366 case RPM:
5367 hdsp->card_name = "RME Hammerfall DSP + RPM";
5368 hdsp->ss_in_channels = RPM_CHANNELS-1;
5369 hdsp->ss_out_channels = RPM_CHANNELS;
5370 hdsp->ds_in_channels = RPM_CHANNELS-1;
5371 hdsp->ds_out_channels = RPM_CHANNELS;
5372 break;
5373
Linus Torvalds1da177e2005-04-16 15:20:36 -07005374 default:
5375 /* should never get here */
5376 break;
5377 }
5378}
5379
Takashi Iwai55e957d2005-11-17 14:52:13 +01005380static void snd_hdsp_initialize_midi_flush (struct hdsp *hdsp)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005381{
5382 snd_hdsp_flush_midi_input (hdsp, 0);
5383 snd_hdsp_flush_midi_input (hdsp, 1);
5384}
5385
Takashi Iwai55e957d2005-11-17 14:52:13 +01005386static int snd_hdsp_create_alsa_devices(struct snd_card *card, struct hdsp *hdsp)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005387{
5388 int err;
Tim Blechmannf9ffc5d2009-02-20 19:38:16 +01005389
Linus Torvalds1da177e2005-04-16 15:20:36 -07005390 if ((err = snd_hdsp_create_pcm(card, hdsp)) < 0) {
Takashi Iwaib0b981192005-10-20 18:29:58 +02005391 snd_printk(KERN_ERR "Hammerfall-DSP: Error creating pcm interface\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07005392 return err;
5393 }
Tim Blechmannf9ffc5d2009-02-20 19:38:16 +01005394
Linus Torvalds1da177e2005-04-16 15:20:36 -07005395
5396 if ((err = snd_hdsp_create_midi(card, hdsp, 0)) < 0) {
Takashi Iwaib0b981192005-10-20 18:29:58 +02005397 snd_printk(KERN_ERR "Hammerfall-DSP: Error creating first midi interface\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07005398 return err;
5399 }
5400
5401 if (hdsp->io_type == Digiface || hdsp->io_type == H9652) {
5402 if ((err = snd_hdsp_create_midi(card, hdsp, 1)) < 0) {
Takashi Iwaib0b981192005-10-20 18:29:58 +02005403 snd_printk(KERN_ERR "Hammerfall-DSP: Error creating second midi interface\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07005404 return err;
5405 }
5406 }
5407
5408 if ((err = snd_hdsp_create_controls(card, hdsp)) < 0) {
Takashi Iwaib0b981192005-10-20 18:29:58 +02005409 snd_printk(KERN_ERR "Hammerfall-DSP: Error creating ctl interface\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07005410 return err;
5411 }
5412
5413 snd_hdsp_proc_init(hdsp);
5414
5415 hdsp->system_sample_rate = -1;
5416 hdsp->playback_pid = -1;
5417 hdsp->capture_pid = -1;
5418 hdsp->capture_substream = NULL;
5419 hdsp->playback_substream = NULL;
5420
5421 if ((err = snd_hdsp_set_defaults(hdsp)) < 0) {
Takashi Iwaib0b981192005-10-20 18:29:58 +02005422 snd_printk(KERN_ERR "Hammerfall-DSP: Error setting default values\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07005423 return err;
5424 }
Tim Blechmannf9ffc5d2009-02-20 19:38:16 +01005425
Linus Torvalds1da177e2005-04-16 15:20:36 -07005426 if (!(hdsp->state & HDSP_InitializationComplete)) {
Clemens Ladischb73c1c12005-09-02 08:49:21 +02005427 strcpy(card->shortname, "Hammerfall DSP");
Tim Blechmannf9ffc5d2009-02-20 19:38:16 +01005428 sprintf(card->longname, "%s at 0x%lx, irq %d", hdsp->card_name,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005429 hdsp->port, hdsp->irq);
Tim Blechmannf9ffc5d2009-02-20 19:38:16 +01005430
Linus Torvalds1da177e2005-04-16 15:20:36 -07005431 if ((err = snd_card_register(card)) < 0) {
Takashi Iwaib0b981192005-10-20 18:29:58 +02005432 snd_printk(KERN_ERR "Hammerfall-DSP: error registering card\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07005433 return err;
5434 }
5435 hdsp->state |= HDSP_InitializationComplete;
5436 }
Tim Blechmannf9ffc5d2009-02-20 19:38:16 +01005437
Linus Torvalds1da177e2005-04-16 15:20:36 -07005438 return 0;
5439}
5440
Linus Torvalds1da177e2005-04-16 15:20:36 -07005441/* load firmware via hotplug fw loader */
Takashi Iwai92eed662008-02-22 18:35:56 +01005442static int hdsp_request_fw_loader(struct hdsp *hdsp)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005443{
5444 const char *fwfile;
5445 const struct firmware *fw;
5446 int err;
Tim Blechmannf9ffc5d2009-02-20 19:38:16 +01005447
Linus Torvalds1da177e2005-04-16 15:20:36 -07005448 if (hdsp->io_type == H9652 || hdsp->io_type == H9632)
5449 return 0;
5450 if (hdsp->io_type == Undefined) {
5451 if ((err = hdsp_get_iobox_version(hdsp)) < 0)
5452 return err;
5453 if (hdsp->io_type == H9652 || hdsp->io_type == H9632)
5454 return 0;
5455 }
Tim Blechmannf9ffc5d2009-02-20 19:38:16 +01005456
Linus Torvalds1da177e2005-04-16 15:20:36 -07005457 /* caution: max length of firmware filename is 30! */
5458 switch (hdsp->io_type) {
Florian Faber28b26e12010-12-01 12:14:47 +01005459 case RPM:
5460 fwfile = "rpm_firmware.bin";
5461 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005462 case Multiface:
5463 if (hdsp->firmware_rev == 0xa)
5464 fwfile = "multiface_firmware.bin";
5465 else
5466 fwfile = "multiface_firmware_rev11.bin";
5467 break;
5468 case Digiface:
5469 if (hdsp->firmware_rev == 0xa)
5470 fwfile = "digiface_firmware.bin";
5471 else
5472 fwfile = "digiface_firmware_rev11.bin";
5473 break;
5474 default:
5475 snd_printk(KERN_ERR "Hammerfall-DSP: invalid io_type %d\n", hdsp->io_type);
5476 return -EINVAL;
5477 }
5478
5479 if (request_firmware(&fw, fwfile, &hdsp->pci->dev)) {
5480 snd_printk(KERN_ERR "Hammerfall-DSP: cannot load firmware %s\n", fwfile);
5481 return -ENOENT;
5482 }
Takashi Iwai90caaef2012-11-22 16:55:11 +01005483 if (fw->size < HDSP_FIRMWARE_SIZE) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005484 snd_printk(KERN_ERR "Hammerfall-DSP: too short firmware size %d (expected %d)\n",
Takashi Iwai90caaef2012-11-22 16:55:11 +01005485 (int)fw->size, HDSP_FIRMWARE_SIZE);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005486 return -EINVAL;
5487 }
Thomas Charbonnel7679a032005-04-25 11:35:29 +02005488
Takashi Iwai90caaef2012-11-22 16:55:11 +01005489 hdsp->firmware = fw;
Tim Blechmannf9ffc5d2009-02-20 19:38:16 +01005490
Linus Torvalds1da177e2005-04-16 15:20:36 -07005491 hdsp->state |= HDSP_FirmwareCached;
5492
5493 if ((err = snd_hdsp_load_firmware_from_cache(hdsp)) < 0)
5494 return err;
Tim Blechmannf9ffc5d2009-02-20 19:38:16 +01005495
Linus Torvalds1da177e2005-04-16 15:20:36 -07005496 if (!(hdsp->state & HDSP_InitializationComplete)) {
Takashi Iwaib0b981192005-10-20 18:29:58 +02005497 if ((err = snd_hdsp_enable_io(hdsp)) < 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005498 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005499
5500 if ((err = snd_hdsp_create_hwdep(hdsp->card, hdsp)) < 0) {
Takashi Iwaib0b981192005-10-20 18:29:58 +02005501 snd_printk(KERN_ERR "Hammerfall-DSP: error creating hwdep device\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07005502 return err;
5503 }
5504 snd_hdsp_initialize_channels(hdsp);
5505 snd_hdsp_initialize_midi_flush(hdsp);
5506 if ((err = snd_hdsp_create_alsa_devices(hdsp->card, hdsp)) < 0) {
Takashi Iwaib0b981192005-10-20 18:29:58 +02005507 snd_printk(KERN_ERR "Hammerfall-DSP: error creating alsa devices\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07005508 return err;
5509 }
5510 }
5511 return 0;
5512}
Linus Torvalds1da177e2005-04-16 15:20:36 -07005513
Bill Pembertone23e7a12012-12-06 12:35:10 -05005514static int snd_hdsp_create(struct snd_card *card,
5515 struct hdsp *hdsp)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005516{
5517 struct pci_dev *pci = hdsp->pci;
5518 int err;
5519 int is_9652 = 0;
5520 int is_9632 = 0;
5521
5522 hdsp->irq = -1;
5523 hdsp->state = 0;
5524 hdsp->midi[0].rmidi = NULL;
5525 hdsp->midi[1].rmidi = NULL;
5526 hdsp->midi[0].input = NULL;
5527 hdsp->midi[1].input = NULL;
5528 hdsp->midi[0].output = NULL;
5529 hdsp->midi[1].output = NULL;
5530 hdsp->midi[0].pending = 0;
5531 hdsp->midi[1].pending = 0;
5532 spin_lock_init(&hdsp->midi[0].lock);
5533 spin_lock_init(&hdsp->midi[1].lock);
5534 hdsp->iobase = NULL;
5535 hdsp->control_register = 0;
5536 hdsp->control2_register = 0;
5537 hdsp->io_type = Undefined;
5538 hdsp->max_channels = 26;
5539
5540 hdsp->card = card;
Tim Blechmannf9ffc5d2009-02-20 19:38:16 +01005541
Linus Torvalds1da177e2005-04-16 15:20:36 -07005542 spin_lock_init(&hdsp->lock);
5543
5544 tasklet_init(&hdsp->midi_tasklet, hdsp_midi_tasklet, (unsigned long)hdsp);
Tim Blechmannf9ffc5d2009-02-20 19:38:16 +01005545
Linus Torvalds1da177e2005-04-16 15:20:36 -07005546 pci_read_config_word(hdsp->pci, PCI_CLASS_REVISION, &hdsp->firmware_rev);
5547 hdsp->firmware_rev &= 0xff;
Tim Blechmannf9ffc5d2009-02-20 19:38:16 +01005548
Linus Torvalds1da177e2005-04-16 15:20:36 -07005549 /* From Martin Bjoernsen :
5550 "It is important that the card's latency timer register in
5551 the PCI configuration space is set to a value much larger
5552 than 0 by the computer's BIOS or the driver.
5553 The windows driver always sets this 8 bit register [...]
5554 to its maximum 255 to avoid problems with some computers."
5555 */
5556 pci_write_config_byte(hdsp->pci, PCI_LATENCY_TIMER, 0xFF);
Tim Blechmannf9ffc5d2009-02-20 19:38:16 +01005557
Linus Torvalds1da177e2005-04-16 15:20:36 -07005558 strcpy(card->driver, "H-DSP");
5559 strcpy(card->mixername, "Xilinx FPGA");
5560
Takashi Iwaib0b981192005-10-20 18:29:58 +02005561 if (hdsp->firmware_rev < 0xa)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005562 return -ENODEV;
Takashi Iwaib0b981192005-10-20 18:29:58 +02005563 else if (hdsp->firmware_rev < 0x64)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005564 hdsp->card_name = "RME Hammerfall DSP";
Takashi Iwaib0b981192005-10-20 18:29:58 +02005565 else if (hdsp->firmware_rev < 0x96) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005566 hdsp->card_name = "RME HDSP 9652";
5567 is_9652 = 1;
5568 } else {
5569 hdsp->card_name = "RME HDSP 9632";
5570 hdsp->max_channels = 16;
Tim Blechmannf9ffc5d2009-02-20 19:38:16 +01005571 is_9632 = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005572 }
5573
Takashi Iwaib0b981192005-10-20 18:29:58 +02005574 if ((err = pci_enable_device(pci)) < 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005575 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005576
5577 pci_set_master(hdsp->pci);
5578
5579 if ((err = pci_request_regions(pci, "hdsp")) < 0)
5580 return err;
5581 hdsp->port = pci_resource_start(pci, 0);
5582 if ((hdsp->iobase = ioremap_nocache(hdsp->port, HDSP_IO_EXTENT)) == NULL) {
Takashi Iwaib0b981192005-10-20 18:29:58 +02005583 snd_printk(KERN_ERR "Hammerfall-DSP: unable to remap region 0x%lx-0x%lx\n", hdsp->port, hdsp->port + HDSP_IO_EXTENT - 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005584 return -EBUSY;
5585 }
5586
Takashi Iwai437a5a42006-11-21 12:14:23 +01005587 if (request_irq(pci->irq, snd_hdsp_interrupt, IRQF_SHARED,
Takashi Iwai934c2b62011-06-10 16:36:37 +02005588 KBUILD_MODNAME, hdsp)) {
Takashi Iwaib0b981192005-10-20 18:29:58 +02005589 snd_printk(KERN_ERR "Hammerfall-DSP: unable to use IRQ %d\n", pci->irq);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005590 return -EBUSY;
5591 }
5592
5593 hdsp->irq = pci->irq;
Remy Bruno176546a2006-10-16 12:32:53 +02005594 hdsp->precise_ptr = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005595 hdsp->use_midi_tasklet = 1;
Remy Brunod7923b22006-10-17 12:41:56 +02005596 hdsp->dds_value = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005597
Takashi Iwaib0b981192005-10-20 18:29:58 +02005598 if ((err = snd_hdsp_initialize_memory(hdsp)) < 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005599 return err;
Tim Blechmannf9ffc5d2009-02-20 19:38:16 +01005600
Linus Torvalds1da177e2005-04-16 15:20:36 -07005601 if (!is_9652 && !is_9632) {
Tim Blechmanne588ed82009-02-20 19:30:35 +01005602 /* we wait a maximum of 10 seconds to let freshly
5603 * inserted cardbus cards do their hardware init */
5604 err = hdsp_wait_for_iobox(hdsp, 1000, 10);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005605
Tim Blechmann00c9ddd2008-11-09 12:50:52 +01005606 if (err < 0)
5607 return err;
5608
Linus Torvalds1da177e2005-04-16 15:20:36 -07005609 if ((hdsp_read (hdsp, HDSP_statusRegister) & HDSP_DllError) != 0) {
Takashi Iwaib0b981192005-10-20 18:29:58 +02005610 if ((err = hdsp_request_fw_loader(hdsp)) < 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005611 /* we don't fail as this can happen
5612 if userspace is not ready for
5613 firmware upload
5614 */
Takashi Iwaib0b981192005-10-20 18:29:58 +02005615 snd_printk(KERN_ERR "Hammerfall-DSP: couldn't get firmware from userspace. try using hdsploader\n");
5616 else
Linus Torvalds1da177e2005-04-16 15:20:36 -07005617 /* init is complete, we return */
5618 return 0;
Tim Blechmann00c9ddd2008-11-09 12:50:52 +01005619 /* we defer initialization */
Takashi Iwaib0b981192005-10-20 18:29:58 +02005620 snd_printk(KERN_INFO "Hammerfall-DSP: card initialization pending : waiting for firmware\n");
5621 if ((err = snd_hdsp_create_hwdep(card, hdsp)) < 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005622 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005623 return 0;
5624 } else {
Tim Blechmannf9ffc5d2009-02-20 19:38:16 +01005625 snd_printk(KERN_INFO "Hammerfall-DSP: Firmware already present, initializing card.\n");
Florian Faber28b26e12010-12-01 12:14:47 +01005626 if (hdsp_read(hdsp, HDSP_status2Register) & HDSP_version2)
5627 hdsp->io_type = RPM;
5628 else if (hdsp_read(hdsp, HDSP_status2Register) & HDSP_version1)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005629 hdsp->io_type = Multiface;
Tim Blechmannf9ffc5d2009-02-20 19:38:16 +01005630 else
Linus Torvalds1da177e2005-04-16 15:20:36 -07005631 hdsp->io_type = Digiface;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005632 }
5633 }
Tim Blechmannf9ffc5d2009-02-20 19:38:16 +01005634
Takashi Iwaib0b981192005-10-20 18:29:58 +02005635 if ((err = snd_hdsp_enable_io(hdsp)) != 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005636 return err;
Tim Blechmannf9ffc5d2009-02-20 19:38:16 +01005637
Takashi Iwaib0b981192005-10-20 18:29:58 +02005638 if (is_9652)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005639 hdsp->io_type = H9652;
Tim Blechmannf9ffc5d2009-02-20 19:38:16 +01005640
Takashi Iwaib0b981192005-10-20 18:29:58 +02005641 if (is_9632)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005642 hdsp->io_type = H9632;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005643
Takashi Iwaib0b981192005-10-20 18:29:58 +02005644 if ((err = snd_hdsp_create_hwdep(card, hdsp)) < 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005645 return err;
Tim Blechmannf9ffc5d2009-02-20 19:38:16 +01005646
Linus Torvalds1da177e2005-04-16 15:20:36 -07005647 snd_hdsp_initialize_channels(hdsp);
5648 snd_hdsp_initialize_midi_flush(hdsp);
5649
Tim Blechmannf9ffc5d2009-02-20 19:38:16 +01005650 hdsp->state |= HDSP_FirmwareLoaded;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005651
Takashi Iwaib0b981192005-10-20 18:29:58 +02005652 if ((err = snd_hdsp_create_alsa_devices(card, hdsp)) < 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005653 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005654
Tim Blechmannf9ffc5d2009-02-20 19:38:16 +01005655 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005656}
5657
Takashi Iwai55e957d2005-11-17 14:52:13 +01005658static int snd_hdsp_free(struct hdsp *hdsp)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005659{
5660 if (hdsp->port) {
5661 /* stop the audio, and cancel all interrupts */
5662 tasklet_kill(&hdsp->midi_tasklet);
5663 hdsp->control_register &= ~(HDSP_Start|HDSP_AudioInterruptEnable|HDSP_Midi0InterruptEnable|HDSP_Midi1InterruptEnable);
5664 hdsp_write (hdsp, HDSP_controlRegister, hdsp->control_register);
5665 }
5666
5667 if (hdsp->irq >= 0)
5668 free_irq(hdsp->irq, (void *)hdsp);
5669
5670 snd_hdsp_free_buffers(hdsp);
Tim Blechmannf9ffc5d2009-02-20 19:38:16 +01005671
Takashi Iwai90caaef2012-11-22 16:55:11 +01005672 if (hdsp->firmware)
5673 release_firmware(hdsp->firmware);
5674 vfree(hdsp->fw_uploaded);
5675
Linus Torvalds1da177e2005-04-16 15:20:36 -07005676 if (hdsp->iobase)
5677 iounmap(hdsp->iobase);
5678
5679 if (hdsp->port)
5680 pci_release_regions(hdsp->pci);
Tim Blechmannf9ffc5d2009-02-20 19:38:16 +01005681
Linus Torvalds1da177e2005-04-16 15:20:36 -07005682 pci_disable_device(hdsp->pci);
5683 return 0;
5684}
5685
Takashi Iwai55e957d2005-11-17 14:52:13 +01005686static void snd_hdsp_card_free(struct snd_card *card)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005687{
Joe Perches9fe856e2010-09-04 18:52:54 -07005688 struct hdsp *hdsp = card->private_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005689
5690 if (hdsp)
5691 snd_hdsp_free(hdsp);
5692}
5693
Bill Pembertone23e7a12012-12-06 12:35:10 -05005694static int snd_hdsp_probe(struct pci_dev *pci,
5695 const struct pci_device_id *pci_id)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005696{
5697 static int dev;
Takashi Iwai55e957d2005-11-17 14:52:13 +01005698 struct hdsp *hdsp;
5699 struct snd_card *card;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005700 int err;
5701
5702 if (dev >= SNDRV_CARDS)
5703 return -ENODEV;
5704 if (!enable[dev]) {
5705 dev++;
5706 return -ENOENT;
5707 }
5708
Takashi Iwaie58de7b2008-12-28 16:44:30 +01005709 err = snd_card_create(index[dev], id[dev], THIS_MODULE,
5710 sizeof(struct hdsp), &card);
5711 if (err < 0)
5712 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005713
Joe Perches9fe856e2010-09-04 18:52:54 -07005714 hdsp = card->private_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005715 card->private_free = snd_hdsp_card_free;
5716 hdsp->dev = dev;
5717 hdsp->pci = pci;
5718 snd_card_set_dev(card, &pci->dev);
5719
5720 if ((err = snd_hdsp_create(card, hdsp)) < 0) {
5721 snd_card_free(card);
5722 return err;
5723 }
5724
5725 strcpy(card->shortname, "Hammerfall DSP");
Tim Blechmannf9ffc5d2009-02-20 19:38:16 +01005726 sprintf(card->longname, "%s at 0x%lx, irq %d", hdsp->card_name,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005727 hdsp->port, hdsp->irq);
5728
5729 if ((err = snd_card_register(card)) < 0) {
5730 snd_card_free(card);
5731 return err;
5732 }
5733 pci_set_drvdata(pci, card);
5734 dev++;
5735 return 0;
5736}
5737
Bill Pembertone23e7a12012-12-06 12:35:10 -05005738static void snd_hdsp_remove(struct pci_dev *pci)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005739{
5740 snd_card_free(pci_get_drvdata(pci));
5741 pci_set_drvdata(pci, NULL);
5742}
5743
Takashi Iwaie9f66d92012-04-24 12:25:00 +02005744static struct pci_driver hdsp_driver = {
Takashi Iwai3733e422011-06-10 16:20:20 +02005745 .name = KBUILD_MODNAME,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005746 .id_table = snd_hdsp_ids,
5747 .probe = snd_hdsp_probe,
Bill Pembertone23e7a12012-12-06 12:35:10 -05005748 .remove = snd_hdsp_remove,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005749};
5750
Takashi Iwaie9f66d92012-04-24 12:25:00 +02005751module_pci_driver(hdsp_driver);