xref: /kernel/linux/linux-5.10/sound/pci/rme9652/hdsp.c (revision 8c2ecf20)
18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci *   ALSA driver for RME Hammerfall DSP audio interface(s)
48c2ecf20Sopenharmony_ci *
58c2ecf20Sopenharmony_ci *      Copyright (c) 2002  Paul Davis
68c2ecf20Sopenharmony_ci *                          Marcus Andersson
78c2ecf20Sopenharmony_ci *                          Thomas Charbonnel
88c2ecf20Sopenharmony_ci */
98c2ecf20Sopenharmony_ci
108c2ecf20Sopenharmony_ci#include <linux/init.h>
118c2ecf20Sopenharmony_ci#include <linux/delay.h>
128c2ecf20Sopenharmony_ci#include <linux/interrupt.h>
138c2ecf20Sopenharmony_ci#include <linux/pci.h>
148c2ecf20Sopenharmony_ci#include <linux/firmware.h>
158c2ecf20Sopenharmony_ci#include <linux/module.h>
168c2ecf20Sopenharmony_ci#include <linux/math64.h>
178c2ecf20Sopenharmony_ci#include <linux/vmalloc.h>
188c2ecf20Sopenharmony_ci#include <linux/io.h>
198c2ecf20Sopenharmony_ci#include <linux/nospec.h>
208c2ecf20Sopenharmony_ci
218c2ecf20Sopenharmony_ci#include <sound/core.h>
228c2ecf20Sopenharmony_ci#include <sound/control.h>
238c2ecf20Sopenharmony_ci#include <sound/pcm.h>
248c2ecf20Sopenharmony_ci#include <sound/info.h>
258c2ecf20Sopenharmony_ci#include <sound/asoundef.h>
268c2ecf20Sopenharmony_ci#include <sound/rawmidi.h>
278c2ecf20Sopenharmony_ci#include <sound/hwdep.h>
288c2ecf20Sopenharmony_ci#include <sound/initval.h>
298c2ecf20Sopenharmony_ci#include <sound/hdsp.h>
308c2ecf20Sopenharmony_ci
318c2ecf20Sopenharmony_ci#include <asm/byteorder.h>
328c2ecf20Sopenharmony_ci#include <asm/current.h>
338c2ecf20Sopenharmony_ci
348c2ecf20Sopenharmony_cistatic int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX;	/* Index 0-MAX */
358c2ecf20Sopenharmony_cistatic char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR;	/* ID for this card */
368c2ecf20Sopenharmony_cistatic bool enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE_PNP;	/* Enable this card */
378c2ecf20Sopenharmony_ci
388c2ecf20Sopenharmony_cimodule_param_array(index, int, NULL, 0444);
398c2ecf20Sopenharmony_ciMODULE_PARM_DESC(index, "Index value for RME Hammerfall DSP interface.");
408c2ecf20Sopenharmony_cimodule_param_array(id, charp, NULL, 0444);
418c2ecf20Sopenharmony_ciMODULE_PARM_DESC(id, "ID string for RME Hammerfall DSP interface.");
428c2ecf20Sopenharmony_cimodule_param_array(enable, bool, NULL, 0444);
438c2ecf20Sopenharmony_ciMODULE_PARM_DESC(enable, "Enable/disable specific Hammerfall DSP soundcards.");
448c2ecf20Sopenharmony_ciMODULE_AUTHOR("Paul Davis <paul@linuxaudiosystems.com>, Marcus Andersson, Thomas Charbonnel <thomas@undata.org>");
458c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("RME Hammerfall DSP");
468c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL");
478c2ecf20Sopenharmony_ciMODULE_SUPPORTED_DEVICE("{{RME Hammerfall-DSP},"
488c2ecf20Sopenharmony_ci	        "{RME HDSP-9652},"
498c2ecf20Sopenharmony_ci		"{RME HDSP-9632}}");
508c2ecf20Sopenharmony_ciMODULE_FIRMWARE("rpm_firmware.bin");
518c2ecf20Sopenharmony_ciMODULE_FIRMWARE("multiface_firmware.bin");
528c2ecf20Sopenharmony_ciMODULE_FIRMWARE("multiface_firmware_rev11.bin");
538c2ecf20Sopenharmony_ciMODULE_FIRMWARE("digiface_firmware.bin");
548c2ecf20Sopenharmony_ciMODULE_FIRMWARE("digiface_firmware_rev11.bin");
558c2ecf20Sopenharmony_ci
568c2ecf20Sopenharmony_ci#define HDSP_MAX_CHANNELS        26
578c2ecf20Sopenharmony_ci#define HDSP_MAX_DS_CHANNELS     14
588c2ecf20Sopenharmony_ci#define HDSP_MAX_QS_CHANNELS     8
598c2ecf20Sopenharmony_ci#define DIGIFACE_SS_CHANNELS     26
608c2ecf20Sopenharmony_ci#define DIGIFACE_DS_CHANNELS     14
618c2ecf20Sopenharmony_ci#define MULTIFACE_SS_CHANNELS    18
628c2ecf20Sopenharmony_ci#define MULTIFACE_DS_CHANNELS    14
638c2ecf20Sopenharmony_ci#define H9652_SS_CHANNELS        26
648c2ecf20Sopenharmony_ci#define H9652_DS_CHANNELS        14
658c2ecf20Sopenharmony_ci/* This does not include possible Analog Extension Boards
668c2ecf20Sopenharmony_ci   AEBs are detected at card initialization
678c2ecf20Sopenharmony_ci*/
688c2ecf20Sopenharmony_ci#define H9632_SS_CHANNELS	 12
698c2ecf20Sopenharmony_ci#define H9632_DS_CHANNELS	 8
708c2ecf20Sopenharmony_ci#define H9632_QS_CHANNELS	 4
718c2ecf20Sopenharmony_ci#define RPM_CHANNELS             6
728c2ecf20Sopenharmony_ci
738c2ecf20Sopenharmony_ci/* Write registers. These are defined as byte-offsets from the iobase value.
748c2ecf20Sopenharmony_ci */
758c2ecf20Sopenharmony_ci#define HDSP_resetPointer               0
768c2ecf20Sopenharmony_ci#define HDSP_freqReg			0
778c2ecf20Sopenharmony_ci#define HDSP_outputBufferAddress	32
788c2ecf20Sopenharmony_ci#define HDSP_inputBufferAddress		36
798c2ecf20Sopenharmony_ci#define HDSP_controlRegister		64
808c2ecf20Sopenharmony_ci#define HDSP_interruptConfirmation	96
818c2ecf20Sopenharmony_ci#define HDSP_outputEnable	  	128
828c2ecf20Sopenharmony_ci#define HDSP_control2Reg		256
838c2ecf20Sopenharmony_ci#define HDSP_midiDataOut0  		352
848c2ecf20Sopenharmony_ci#define HDSP_midiDataOut1  		356
858c2ecf20Sopenharmony_ci#define HDSP_fifoData  			368
868c2ecf20Sopenharmony_ci#define HDSP_inputEnable	 	384
878c2ecf20Sopenharmony_ci
888c2ecf20Sopenharmony_ci/* Read registers. These are defined as byte-offsets from the iobase value
898c2ecf20Sopenharmony_ci */
908c2ecf20Sopenharmony_ci
918c2ecf20Sopenharmony_ci#define HDSP_statusRegister    0
928c2ecf20Sopenharmony_ci#define HDSP_timecode        128
938c2ecf20Sopenharmony_ci#define HDSP_status2Register 192
948c2ecf20Sopenharmony_ci#define HDSP_midiDataIn0     360
958c2ecf20Sopenharmony_ci#define HDSP_midiDataIn1     364
968c2ecf20Sopenharmony_ci#define HDSP_midiStatusOut0  384
978c2ecf20Sopenharmony_ci#define HDSP_midiStatusOut1  388
988c2ecf20Sopenharmony_ci#define HDSP_midiStatusIn0   392
998c2ecf20Sopenharmony_ci#define HDSP_midiStatusIn1   396
1008c2ecf20Sopenharmony_ci#define HDSP_fifoStatus      400
1018c2ecf20Sopenharmony_ci
1028c2ecf20Sopenharmony_ci/* the meters are regular i/o-mapped registers, but offset
1038c2ecf20Sopenharmony_ci   considerably from the rest. the peak registers are reset
1048c2ecf20Sopenharmony_ci   when read; the least-significant 4 bits are full-scale counters;
1058c2ecf20Sopenharmony_ci   the actual peak value is in the most-significant 24 bits.
1068c2ecf20Sopenharmony_ci*/
1078c2ecf20Sopenharmony_ci
1088c2ecf20Sopenharmony_ci#define HDSP_playbackPeakLevel  4096  /* 26 * 32 bit values */
1098c2ecf20Sopenharmony_ci#define HDSP_inputPeakLevel     4224  /* 26 * 32 bit values */
1108c2ecf20Sopenharmony_ci#define HDSP_outputPeakLevel    4352  /* (26+2) * 32 bit values */
1118c2ecf20Sopenharmony_ci#define HDSP_playbackRmsLevel   4612  /* 26 * 64 bit values */
1128c2ecf20Sopenharmony_ci#define HDSP_inputRmsLevel      4868  /* 26 * 64 bit values */
1138c2ecf20Sopenharmony_ci
1148c2ecf20Sopenharmony_ci
1158c2ecf20Sopenharmony_ci/* This is for H9652 cards
1168c2ecf20Sopenharmony_ci   Peak values are read downward from the base
1178c2ecf20Sopenharmony_ci   Rms values are read upward
1188c2ecf20Sopenharmony_ci   There are rms values for the outputs too
1198c2ecf20Sopenharmony_ci   26*3 values are read in ss mode
1208c2ecf20Sopenharmony_ci   14*3 in ds mode, with no gap between values
1218c2ecf20Sopenharmony_ci*/
1228c2ecf20Sopenharmony_ci#define HDSP_9652_peakBase	7164
1238c2ecf20Sopenharmony_ci#define HDSP_9652_rmsBase	4096
1248c2ecf20Sopenharmony_ci
1258c2ecf20Sopenharmony_ci/* c.f. the hdsp_9632_meters_t struct */
1268c2ecf20Sopenharmony_ci#define HDSP_9632_metersBase	4096
1278c2ecf20Sopenharmony_ci
1288c2ecf20Sopenharmony_ci#define HDSP_IO_EXTENT     7168
1298c2ecf20Sopenharmony_ci
1308c2ecf20Sopenharmony_ci/* control2 register bits */
1318c2ecf20Sopenharmony_ci
1328c2ecf20Sopenharmony_ci#define HDSP_TMS                0x01
1338c2ecf20Sopenharmony_ci#define HDSP_TCK                0x02
1348c2ecf20Sopenharmony_ci#define HDSP_TDI                0x04
1358c2ecf20Sopenharmony_ci#define HDSP_JTAG               0x08
1368c2ecf20Sopenharmony_ci#define HDSP_PWDN               0x10
1378c2ecf20Sopenharmony_ci#define HDSP_PROGRAM	        0x020
1388c2ecf20Sopenharmony_ci#define HDSP_CONFIG_MODE_0	0x040
1398c2ecf20Sopenharmony_ci#define HDSP_CONFIG_MODE_1	0x080
1408c2ecf20Sopenharmony_ci#define HDSP_VERSION_BIT	(0x100 | HDSP_S_LOAD)
1418c2ecf20Sopenharmony_ci#define HDSP_BIGENDIAN_MODE     0x200
1428c2ecf20Sopenharmony_ci#define HDSP_RD_MULTIPLE        0x400
1438c2ecf20Sopenharmony_ci#define HDSP_9652_ENABLE_MIXER  0x800
1448c2ecf20Sopenharmony_ci#define HDSP_S200		0x800
1458c2ecf20Sopenharmony_ci#define HDSP_S300		(0x100 | HDSP_S200) /* dummy, purpose of 0x100 unknown */
1468c2ecf20Sopenharmony_ci#define HDSP_CYCLIC_MODE	0x1000
1478c2ecf20Sopenharmony_ci#define HDSP_TDO                0x10000000
1488c2ecf20Sopenharmony_ci
1498c2ecf20Sopenharmony_ci#define HDSP_S_PROGRAM	    (HDSP_CYCLIC_MODE|HDSP_PROGRAM|HDSP_CONFIG_MODE_0)
1508c2ecf20Sopenharmony_ci#define HDSP_S_LOAD	    (HDSP_CYCLIC_MODE|HDSP_PROGRAM|HDSP_CONFIG_MODE_1)
1518c2ecf20Sopenharmony_ci
1528c2ecf20Sopenharmony_ci/* Control Register bits */
1538c2ecf20Sopenharmony_ci
1548c2ecf20Sopenharmony_ci#define HDSP_Start                (1<<0)  /* start engine */
1558c2ecf20Sopenharmony_ci#define HDSP_Latency0             (1<<1)  /* buffer size = 2^n where n is defined by Latency{2,1,0} */
1568c2ecf20Sopenharmony_ci#define HDSP_Latency1             (1<<2)  /* [ see above ] */
1578c2ecf20Sopenharmony_ci#define HDSP_Latency2             (1<<3)  /* [ see above ] */
1588c2ecf20Sopenharmony_ci#define HDSP_ClockModeMaster      (1<<4)  /* 1=Master, 0=Slave/Autosync */
1598c2ecf20Sopenharmony_ci#define HDSP_AudioInterruptEnable (1<<5)  /* what do you think ? */
1608c2ecf20Sopenharmony_ci#define HDSP_Frequency0           (1<<6)  /* 0=44.1kHz/88.2kHz/176.4kHz 1=48kHz/96kHz/192kHz */
1618c2ecf20Sopenharmony_ci#define HDSP_Frequency1           (1<<7)  /* 0=32kHz/64kHz/128kHz */
1628c2ecf20Sopenharmony_ci#define HDSP_DoubleSpeed          (1<<8)  /* 0=normal speed, 1=double speed */
1638c2ecf20Sopenharmony_ci#define HDSP_SPDIFProfessional    (1<<9)  /* 0=consumer, 1=professional */
1648c2ecf20Sopenharmony_ci#define HDSP_SPDIFEmphasis        (1<<10) /* 0=none, 1=on */
1658c2ecf20Sopenharmony_ci#define HDSP_SPDIFNonAudio        (1<<11) /* 0=off, 1=on */
1668c2ecf20Sopenharmony_ci#define HDSP_SPDIFOpticalOut      (1<<12) /* 1=use 1st ADAT connector for SPDIF, 0=do not */
1678c2ecf20Sopenharmony_ci#define HDSP_SyncRef2             (1<<13)
1688c2ecf20Sopenharmony_ci#define HDSP_SPDIFInputSelect0    (1<<14)
1698c2ecf20Sopenharmony_ci#define HDSP_SPDIFInputSelect1    (1<<15)
1708c2ecf20Sopenharmony_ci#define HDSP_SyncRef0             (1<<16)
1718c2ecf20Sopenharmony_ci#define HDSP_SyncRef1             (1<<17)
1728c2ecf20Sopenharmony_ci#define HDSP_AnalogExtensionBoard (1<<18) /* For H9632 cards */
1738c2ecf20Sopenharmony_ci#define HDSP_XLRBreakoutCable     (1<<20) /* For H9632 cards */
1748c2ecf20Sopenharmony_ci#define HDSP_Midi0InterruptEnable (1<<22)
1758c2ecf20Sopenharmony_ci#define HDSP_Midi1InterruptEnable (1<<23)
1768c2ecf20Sopenharmony_ci#define HDSP_LineOut              (1<<24)
1778c2ecf20Sopenharmony_ci#define HDSP_ADGain0		  (1<<25) /* From here : H9632 specific */
1788c2ecf20Sopenharmony_ci#define HDSP_ADGain1		  (1<<26)
1798c2ecf20Sopenharmony_ci#define HDSP_DAGain0		  (1<<27)
1808c2ecf20Sopenharmony_ci#define HDSP_DAGain1		  (1<<28)
1818c2ecf20Sopenharmony_ci#define HDSP_PhoneGain0		  (1<<29)
1828c2ecf20Sopenharmony_ci#define HDSP_PhoneGain1		  (1<<30)
1838c2ecf20Sopenharmony_ci#define HDSP_QuadSpeed	  	  (1<<31)
1848c2ecf20Sopenharmony_ci
1858c2ecf20Sopenharmony_ci/* RPM uses some of the registers for special purposes */
1868c2ecf20Sopenharmony_ci#define HDSP_RPM_Inp12            0x04A00
1878c2ecf20Sopenharmony_ci#define HDSP_RPM_Inp12_Phon_6dB   0x00800  /* Dolby */
1888c2ecf20Sopenharmony_ci#define HDSP_RPM_Inp12_Phon_0dB   0x00000  /* .. */
1898c2ecf20Sopenharmony_ci#define HDSP_RPM_Inp12_Phon_n6dB  0x04000  /* inp_0 */
1908c2ecf20Sopenharmony_ci#define HDSP_RPM_Inp12_Line_0dB   0x04200  /* Dolby+PRO */
1918c2ecf20Sopenharmony_ci#define HDSP_RPM_Inp12_Line_n6dB  0x00200  /* PRO */
1928c2ecf20Sopenharmony_ci
1938c2ecf20Sopenharmony_ci#define HDSP_RPM_Inp34            0x32000
1948c2ecf20Sopenharmony_ci#define HDSP_RPM_Inp34_Phon_6dB   0x20000  /* SyncRef1 */
1958c2ecf20Sopenharmony_ci#define HDSP_RPM_Inp34_Phon_0dB   0x00000  /* .. */
1968c2ecf20Sopenharmony_ci#define HDSP_RPM_Inp34_Phon_n6dB  0x02000  /* SyncRef2 */
1978c2ecf20Sopenharmony_ci#define HDSP_RPM_Inp34_Line_0dB   0x30000  /* SyncRef1+SyncRef0 */
1988c2ecf20Sopenharmony_ci#define HDSP_RPM_Inp34_Line_n6dB  0x10000  /* SyncRef0 */
1998c2ecf20Sopenharmony_ci
2008c2ecf20Sopenharmony_ci#define HDSP_RPM_Bypass           0x01000
2018c2ecf20Sopenharmony_ci
2028c2ecf20Sopenharmony_ci#define HDSP_RPM_Disconnect       0x00001
2038c2ecf20Sopenharmony_ci
2048c2ecf20Sopenharmony_ci#define HDSP_ADGainMask       (HDSP_ADGain0|HDSP_ADGain1)
2058c2ecf20Sopenharmony_ci#define HDSP_ADGainMinus10dBV  HDSP_ADGainMask
2068c2ecf20Sopenharmony_ci#define HDSP_ADGainPlus4dBu   (HDSP_ADGain0)
2078c2ecf20Sopenharmony_ci#define HDSP_ADGainLowGain     0
2088c2ecf20Sopenharmony_ci
2098c2ecf20Sopenharmony_ci#define HDSP_DAGainMask         (HDSP_DAGain0|HDSP_DAGain1)
2108c2ecf20Sopenharmony_ci#define HDSP_DAGainHighGain      HDSP_DAGainMask
2118c2ecf20Sopenharmony_ci#define HDSP_DAGainPlus4dBu     (HDSP_DAGain0)
2128c2ecf20Sopenharmony_ci#define HDSP_DAGainMinus10dBV    0
2138c2ecf20Sopenharmony_ci
2148c2ecf20Sopenharmony_ci#define HDSP_PhoneGainMask      (HDSP_PhoneGain0|HDSP_PhoneGain1)
2158c2ecf20Sopenharmony_ci#define HDSP_PhoneGain0dB        HDSP_PhoneGainMask
2168c2ecf20Sopenharmony_ci#define HDSP_PhoneGainMinus6dB  (HDSP_PhoneGain0)
2178c2ecf20Sopenharmony_ci#define HDSP_PhoneGainMinus12dB  0
2188c2ecf20Sopenharmony_ci
2198c2ecf20Sopenharmony_ci#define HDSP_LatencyMask    (HDSP_Latency0|HDSP_Latency1|HDSP_Latency2)
2208c2ecf20Sopenharmony_ci#define HDSP_FrequencyMask  (HDSP_Frequency0|HDSP_Frequency1|HDSP_DoubleSpeed|HDSP_QuadSpeed)
2218c2ecf20Sopenharmony_ci
2228c2ecf20Sopenharmony_ci#define HDSP_SPDIFInputMask    (HDSP_SPDIFInputSelect0|HDSP_SPDIFInputSelect1)
2238c2ecf20Sopenharmony_ci#define HDSP_SPDIFInputADAT1    0
2248c2ecf20Sopenharmony_ci#define HDSP_SPDIFInputCoaxial (HDSP_SPDIFInputSelect0)
2258c2ecf20Sopenharmony_ci#define HDSP_SPDIFInputCdrom   (HDSP_SPDIFInputSelect1)
2268c2ecf20Sopenharmony_ci#define HDSP_SPDIFInputAES     (HDSP_SPDIFInputSelect0|HDSP_SPDIFInputSelect1)
2278c2ecf20Sopenharmony_ci
2288c2ecf20Sopenharmony_ci#define HDSP_SyncRefMask        (HDSP_SyncRef0|HDSP_SyncRef1|HDSP_SyncRef2)
2298c2ecf20Sopenharmony_ci#define HDSP_SyncRef_ADAT1       0
2308c2ecf20Sopenharmony_ci#define HDSP_SyncRef_ADAT2      (HDSP_SyncRef0)
2318c2ecf20Sopenharmony_ci#define HDSP_SyncRef_ADAT3      (HDSP_SyncRef1)
2328c2ecf20Sopenharmony_ci#define HDSP_SyncRef_SPDIF      (HDSP_SyncRef0|HDSP_SyncRef1)
2338c2ecf20Sopenharmony_ci#define HDSP_SyncRef_WORD       (HDSP_SyncRef2)
2348c2ecf20Sopenharmony_ci#define HDSP_SyncRef_ADAT_SYNC  (HDSP_SyncRef0|HDSP_SyncRef2)
2358c2ecf20Sopenharmony_ci
2368c2ecf20Sopenharmony_ci/* Sample Clock Sources */
2378c2ecf20Sopenharmony_ci
2388c2ecf20Sopenharmony_ci#define HDSP_CLOCK_SOURCE_AUTOSYNC           0
2398c2ecf20Sopenharmony_ci#define HDSP_CLOCK_SOURCE_INTERNAL_32KHZ     1
2408c2ecf20Sopenharmony_ci#define HDSP_CLOCK_SOURCE_INTERNAL_44_1KHZ   2
2418c2ecf20Sopenharmony_ci#define HDSP_CLOCK_SOURCE_INTERNAL_48KHZ     3
2428c2ecf20Sopenharmony_ci#define HDSP_CLOCK_SOURCE_INTERNAL_64KHZ     4
2438c2ecf20Sopenharmony_ci#define HDSP_CLOCK_SOURCE_INTERNAL_88_2KHZ   5
2448c2ecf20Sopenharmony_ci#define HDSP_CLOCK_SOURCE_INTERNAL_96KHZ     6
2458c2ecf20Sopenharmony_ci#define HDSP_CLOCK_SOURCE_INTERNAL_128KHZ    7
2468c2ecf20Sopenharmony_ci#define HDSP_CLOCK_SOURCE_INTERNAL_176_4KHZ  8
2478c2ecf20Sopenharmony_ci#define HDSP_CLOCK_SOURCE_INTERNAL_192KHZ    9
2488c2ecf20Sopenharmony_ci
2498c2ecf20Sopenharmony_ci/* Preferred sync reference choices - used by "pref_sync_ref" control switch */
2508c2ecf20Sopenharmony_ci
2518c2ecf20Sopenharmony_ci#define HDSP_SYNC_FROM_WORD      0
2528c2ecf20Sopenharmony_ci#define HDSP_SYNC_FROM_SPDIF     1
2538c2ecf20Sopenharmony_ci#define HDSP_SYNC_FROM_ADAT1     2
2548c2ecf20Sopenharmony_ci#define HDSP_SYNC_FROM_ADAT_SYNC 3
2558c2ecf20Sopenharmony_ci#define HDSP_SYNC_FROM_ADAT2     4
2568c2ecf20Sopenharmony_ci#define HDSP_SYNC_FROM_ADAT3     5
2578c2ecf20Sopenharmony_ci
2588c2ecf20Sopenharmony_ci/* SyncCheck status */
2598c2ecf20Sopenharmony_ci
2608c2ecf20Sopenharmony_ci#define HDSP_SYNC_CHECK_NO_LOCK 0
2618c2ecf20Sopenharmony_ci#define HDSP_SYNC_CHECK_LOCK    1
2628c2ecf20Sopenharmony_ci#define HDSP_SYNC_CHECK_SYNC	2
2638c2ecf20Sopenharmony_ci
2648c2ecf20Sopenharmony_ci/* AutoSync references - used by "autosync_ref" control switch */
2658c2ecf20Sopenharmony_ci
2668c2ecf20Sopenharmony_ci#define HDSP_AUTOSYNC_FROM_WORD      0
2678c2ecf20Sopenharmony_ci#define HDSP_AUTOSYNC_FROM_ADAT_SYNC 1
2688c2ecf20Sopenharmony_ci#define HDSP_AUTOSYNC_FROM_SPDIF     2
2698c2ecf20Sopenharmony_ci#define HDSP_AUTOSYNC_FROM_NONE	     3
2708c2ecf20Sopenharmony_ci#define HDSP_AUTOSYNC_FROM_ADAT1     4
2718c2ecf20Sopenharmony_ci#define HDSP_AUTOSYNC_FROM_ADAT2     5
2728c2ecf20Sopenharmony_ci#define HDSP_AUTOSYNC_FROM_ADAT3     6
2738c2ecf20Sopenharmony_ci
2748c2ecf20Sopenharmony_ci/* Possible sources of S/PDIF input */
2758c2ecf20Sopenharmony_ci
2768c2ecf20Sopenharmony_ci#define HDSP_SPDIFIN_OPTICAL  0	/* optical  (ADAT1) */
2778c2ecf20Sopenharmony_ci#define HDSP_SPDIFIN_COAXIAL  1	/* coaxial (RCA) */
2788c2ecf20Sopenharmony_ci#define HDSP_SPDIFIN_INTERNAL 2	/* internal (CDROM) */
2798c2ecf20Sopenharmony_ci#define HDSP_SPDIFIN_AES      3 /* xlr for H9632 (AES)*/
2808c2ecf20Sopenharmony_ci
2818c2ecf20Sopenharmony_ci#define HDSP_Frequency32KHz    HDSP_Frequency0
2828c2ecf20Sopenharmony_ci#define HDSP_Frequency44_1KHz  HDSP_Frequency1
2838c2ecf20Sopenharmony_ci#define HDSP_Frequency48KHz    (HDSP_Frequency1|HDSP_Frequency0)
2848c2ecf20Sopenharmony_ci#define HDSP_Frequency64KHz    (HDSP_DoubleSpeed|HDSP_Frequency0)
2858c2ecf20Sopenharmony_ci#define HDSP_Frequency88_2KHz  (HDSP_DoubleSpeed|HDSP_Frequency1)
2868c2ecf20Sopenharmony_ci#define HDSP_Frequency96KHz    (HDSP_DoubleSpeed|HDSP_Frequency1|HDSP_Frequency0)
2878c2ecf20Sopenharmony_ci/* For H9632 cards */
2888c2ecf20Sopenharmony_ci#define HDSP_Frequency128KHz   (HDSP_QuadSpeed|HDSP_DoubleSpeed|HDSP_Frequency0)
2898c2ecf20Sopenharmony_ci#define HDSP_Frequency176_4KHz (HDSP_QuadSpeed|HDSP_DoubleSpeed|HDSP_Frequency1)
2908c2ecf20Sopenharmony_ci#define HDSP_Frequency192KHz   (HDSP_QuadSpeed|HDSP_DoubleSpeed|HDSP_Frequency1|HDSP_Frequency0)
2918c2ecf20Sopenharmony_ci/* RME says n = 104857600000000, but in the windows MADI driver, I see:
2928c2ecf20Sopenharmony_ci	return 104857600000000 / rate; // 100 MHz
2938c2ecf20Sopenharmony_ci	return 110100480000000 / rate; // 105 MHz
2948c2ecf20Sopenharmony_ci*/
2958c2ecf20Sopenharmony_ci#define DDS_NUMERATOR 104857600000000ULL;  /*  =  2^20 * 10^8 */
2968c2ecf20Sopenharmony_ci
2978c2ecf20Sopenharmony_ci#define hdsp_encode_latency(x)       (((x)<<1) & HDSP_LatencyMask)
2988c2ecf20Sopenharmony_ci#define hdsp_decode_latency(x)       (((x) & HDSP_LatencyMask)>>1)
2998c2ecf20Sopenharmony_ci
3008c2ecf20Sopenharmony_ci#define hdsp_encode_spdif_in(x) (((x)&0x3)<<14)
3018c2ecf20Sopenharmony_ci#define hdsp_decode_spdif_in(x) (((x)>>14)&0x3)
3028c2ecf20Sopenharmony_ci
3038c2ecf20Sopenharmony_ci/* Status Register bits */
3048c2ecf20Sopenharmony_ci
3058c2ecf20Sopenharmony_ci#define HDSP_audioIRQPending    (1<<0)
3068c2ecf20Sopenharmony_ci#define HDSP_Lock2              (1<<1)     /* this is for Digiface and H9652 */
3078c2ecf20Sopenharmony_ci#define HDSP_spdifFrequency3	HDSP_Lock2 /* this is for H9632 only */
3088c2ecf20Sopenharmony_ci#define HDSP_Lock1              (1<<2)
3098c2ecf20Sopenharmony_ci#define HDSP_Lock0              (1<<3)
3108c2ecf20Sopenharmony_ci#define HDSP_SPDIFSync          (1<<4)
3118c2ecf20Sopenharmony_ci#define HDSP_TimecodeLock       (1<<5)
3128c2ecf20Sopenharmony_ci#define HDSP_BufferPositionMask 0x000FFC0 /* Bit 6..15 : h/w buffer pointer */
3138c2ecf20Sopenharmony_ci#define HDSP_Sync2              (1<<16)
3148c2ecf20Sopenharmony_ci#define HDSP_Sync1              (1<<17)
3158c2ecf20Sopenharmony_ci#define HDSP_Sync0              (1<<18)
3168c2ecf20Sopenharmony_ci#define HDSP_DoubleSpeedStatus  (1<<19)
3178c2ecf20Sopenharmony_ci#define HDSP_ConfigError        (1<<20)
3188c2ecf20Sopenharmony_ci#define HDSP_DllError           (1<<21)
3198c2ecf20Sopenharmony_ci#define HDSP_spdifFrequency0    (1<<22)
3208c2ecf20Sopenharmony_ci#define HDSP_spdifFrequency1    (1<<23)
3218c2ecf20Sopenharmony_ci#define HDSP_spdifFrequency2    (1<<24)
3228c2ecf20Sopenharmony_ci#define HDSP_SPDIFErrorFlag     (1<<25)
3238c2ecf20Sopenharmony_ci#define HDSP_BufferID           (1<<26)
3248c2ecf20Sopenharmony_ci#define HDSP_TimecodeSync       (1<<27)
3258c2ecf20Sopenharmony_ci#define HDSP_AEBO          	(1<<28) /* H9632 specific Analog Extension Boards */
3268c2ecf20Sopenharmony_ci#define HDSP_AEBI		(1<<29) /* 0 = present, 1 = absent */
3278c2ecf20Sopenharmony_ci#define HDSP_midi0IRQPending    (1<<30)
3288c2ecf20Sopenharmony_ci#define HDSP_midi1IRQPending    (1<<31)
3298c2ecf20Sopenharmony_ci
3308c2ecf20Sopenharmony_ci#define HDSP_spdifFrequencyMask    (HDSP_spdifFrequency0|HDSP_spdifFrequency1|HDSP_spdifFrequency2)
3318c2ecf20Sopenharmony_ci#define HDSP_spdifFrequencyMask_9632 (HDSP_spdifFrequency0|\
3328c2ecf20Sopenharmony_ci				      HDSP_spdifFrequency1|\
3338c2ecf20Sopenharmony_ci				      HDSP_spdifFrequency2|\
3348c2ecf20Sopenharmony_ci				      HDSP_spdifFrequency3)
3358c2ecf20Sopenharmony_ci
3368c2ecf20Sopenharmony_ci#define HDSP_spdifFrequency32KHz   (HDSP_spdifFrequency0)
3378c2ecf20Sopenharmony_ci#define HDSP_spdifFrequency44_1KHz (HDSP_spdifFrequency1)
3388c2ecf20Sopenharmony_ci#define HDSP_spdifFrequency48KHz   (HDSP_spdifFrequency0|HDSP_spdifFrequency1)
3398c2ecf20Sopenharmony_ci
3408c2ecf20Sopenharmony_ci#define HDSP_spdifFrequency64KHz   (HDSP_spdifFrequency2)
3418c2ecf20Sopenharmony_ci#define HDSP_spdifFrequency88_2KHz (HDSP_spdifFrequency0|HDSP_spdifFrequency2)
3428c2ecf20Sopenharmony_ci#define HDSP_spdifFrequency96KHz   (HDSP_spdifFrequency2|HDSP_spdifFrequency1)
3438c2ecf20Sopenharmony_ci
3448c2ecf20Sopenharmony_ci/* This is for H9632 cards */
3458c2ecf20Sopenharmony_ci#define HDSP_spdifFrequency128KHz   (HDSP_spdifFrequency0|\
3468c2ecf20Sopenharmony_ci				     HDSP_spdifFrequency1|\
3478c2ecf20Sopenharmony_ci				     HDSP_spdifFrequency2)
3488c2ecf20Sopenharmony_ci#define HDSP_spdifFrequency176_4KHz HDSP_spdifFrequency3
3498c2ecf20Sopenharmony_ci#define HDSP_spdifFrequency192KHz   (HDSP_spdifFrequency3|HDSP_spdifFrequency0)
3508c2ecf20Sopenharmony_ci
3518c2ecf20Sopenharmony_ci/* Status2 Register bits */
3528c2ecf20Sopenharmony_ci
3538c2ecf20Sopenharmony_ci#define HDSP_version0     (1<<0)
3548c2ecf20Sopenharmony_ci#define HDSP_version1     (1<<1)
3558c2ecf20Sopenharmony_ci#define HDSP_version2     (1<<2)
3568c2ecf20Sopenharmony_ci#define HDSP_wc_lock      (1<<3)
3578c2ecf20Sopenharmony_ci#define HDSP_wc_sync      (1<<4)
3588c2ecf20Sopenharmony_ci#define HDSP_inp_freq0    (1<<5)
3598c2ecf20Sopenharmony_ci#define HDSP_inp_freq1    (1<<6)
3608c2ecf20Sopenharmony_ci#define HDSP_inp_freq2    (1<<7)
3618c2ecf20Sopenharmony_ci#define HDSP_SelSyncRef0  (1<<8)
3628c2ecf20Sopenharmony_ci#define HDSP_SelSyncRef1  (1<<9)
3638c2ecf20Sopenharmony_ci#define HDSP_SelSyncRef2  (1<<10)
3648c2ecf20Sopenharmony_ci
3658c2ecf20Sopenharmony_ci#define HDSP_wc_valid (HDSP_wc_lock|HDSP_wc_sync)
3668c2ecf20Sopenharmony_ci
3678c2ecf20Sopenharmony_ci#define HDSP_systemFrequencyMask (HDSP_inp_freq0|HDSP_inp_freq1|HDSP_inp_freq2)
3688c2ecf20Sopenharmony_ci#define HDSP_systemFrequency32   (HDSP_inp_freq0)
3698c2ecf20Sopenharmony_ci#define HDSP_systemFrequency44_1 (HDSP_inp_freq1)
3708c2ecf20Sopenharmony_ci#define HDSP_systemFrequency48   (HDSP_inp_freq0|HDSP_inp_freq1)
3718c2ecf20Sopenharmony_ci#define HDSP_systemFrequency64   (HDSP_inp_freq2)
3728c2ecf20Sopenharmony_ci#define HDSP_systemFrequency88_2 (HDSP_inp_freq0|HDSP_inp_freq2)
3738c2ecf20Sopenharmony_ci#define HDSP_systemFrequency96   (HDSP_inp_freq1|HDSP_inp_freq2)
3748c2ecf20Sopenharmony_ci/* FIXME : more values for 9632 cards ? */
3758c2ecf20Sopenharmony_ci
3768c2ecf20Sopenharmony_ci#define HDSP_SelSyncRefMask        (HDSP_SelSyncRef0|HDSP_SelSyncRef1|HDSP_SelSyncRef2)
3778c2ecf20Sopenharmony_ci#define HDSP_SelSyncRef_ADAT1      0
3788c2ecf20Sopenharmony_ci#define HDSP_SelSyncRef_ADAT2      (HDSP_SelSyncRef0)
3798c2ecf20Sopenharmony_ci#define HDSP_SelSyncRef_ADAT3      (HDSP_SelSyncRef1)
3808c2ecf20Sopenharmony_ci#define HDSP_SelSyncRef_SPDIF      (HDSP_SelSyncRef0|HDSP_SelSyncRef1)
3818c2ecf20Sopenharmony_ci#define HDSP_SelSyncRef_WORD       (HDSP_SelSyncRef2)
3828c2ecf20Sopenharmony_ci#define HDSP_SelSyncRef_ADAT_SYNC  (HDSP_SelSyncRef0|HDSP_SelSyncRef2)
3838c2ecf20Sopenharmony_ci
3848c2ecf20Sopenharmony_ci/* Card state flags */
3858c2ecf20Sopenharmony_ci
3868c2ecf20Sopenharmony_ci#define HDSP_InitializationComplete  (1<<0)
3878c2ecf20Sopenharmony_ci#define HDSP_FirmwareLoaded	     (1<<1)
3888c2ecf20Sopenharmony_ci#define HDSP_FirmwareCached	     (1<<2)
3898c2ecf20Sopenharmony_ci
3908c2ecf20Sopenharmony_ci/* FIFO wait times, defined in terms of 1/10ths of msecs */
3918c2ecf20Sopenharmony_ci
3928c2ecf20Sopenharmony_ci#define HDSP_LONG_WAIT	 5000
3938c2ecf20Sopenharmony_ci#define HDSP_SHORT_WAIT  30
3948c2ecf20Sopenharmony_ci
3958c2ecf20Sopenharmony_ci#define UNITY_GAIN                       32768
3968c2ecf20Sopenharmony_ci#define MINUS_INFINITY_GAIN              0
3978c2ecf20Sopenharmony_ci
3988c2ecf20Sopenharmony_ci/* the size of a substream (1 mono data stream) */
3998c2ecf20Sopenharmony_ci
4008c2ecf20Sopenharmony_ci#define HDSP_CHANNEL_BUFFER_SAMPLES  (16*1024)
4018c2ecf20Sopenharmony_ci#define HDSP_CHANNEL_BUFFER_BYTES    (4*HDSP_CHANNEL_BUFFER_SAMPLES)
4028c2ecf20Sopenharmony_ci
4038c2ecf20Sopenharmony_ci/* the size of the area we need to allocate for DMA transfers. the
4048c2ecf20Sopenharmony_ci   size is the same regardless of the number of channels - the
4058c2ecf20Sopenharmony_ci   Multiface still uses the same memory area.
4068c2ecf20Sopenharmony_ci
4078c2ecf20Sopenharmony_ci   Note that we allocate 1 more channel than is apparently needed
4088c2ecf20Sopenharmony_ci   because the h/w seems to write 1 byte beyond the end of the last
4098c2ecf20Sopenharmony_ci   page. Sigh.
4108c2ecf20Sopenharmony_ci*/
4118c2ecf20Sopenharmony_ci
4128c2ecf20Sopenharmony_ci#define HDSP_DMA_AREA_BYTES ((HDSP_MAX_CHANNELS+1) * HDSP_CHANNEL_BUFFER_BYTES)
4138c2ecf20Sopenharmony_ci#define HDSP_DMA_AREA_KILOBYTES (HDSP_DMA_AREA_BYTES/1024)
4148c2ecf20Sopenharmony_ci
4158c2ecf20Sopenharmony_ci#define HDSP_FIRMWARE_SIZE	(24413 * 4)
4168c2ecf20Sopenharmony_ci
4178c2ecf20Sopenharmony_cistruct hdsp_9632_meters {
4188c2ecf20Sopenharmony_ci    u32 input_peak[16];
4198c2ecf20Sopenharmony_ci    u32 playback_peak[16];
4208c2ecf20Sopenharmony_ci    u32 output_peak[16];
4218c2ecf20Sopenharmony_ci    u32 xxx_peak[16];
4228c2ecf20Sopenharmony_ci    u32 padding[64];
4238c2ecf20Sopenharmony_ci    u32 input_rms_low[16];
4248c2ecf20Sopenharmony_ci    u32 playback_rms_low[16];
4258c2ecf20Sopenharmony_ci    u32 output_rms_low[16];
4268c2ecf20Sopenharmony_ci    u32 xxx_rms_low[16];
4278c2ecf20Sopenharmony_ci    u32 input_rms_high[16];
4288c2ecf20Sopenharmony_ci    u32 playback_rms_high[16];
4298c2ecf20Sopenharmony_ci    u32 output_rms_high[16];
4308c2ecf20Sopenharmony_ci    u32 xxx_rms_high[16];
4318c2ecf20Sopenharmony_ci};
4328c2ecf20Sopenharmony_ci
4338c2ecf20Sopenharmony_cistruct hdsp_midi {
4348c2ecf20Sopenharmony_ci    struct hdsp             *hdsp;
4358c2ecf20Sopenharmony_ci    int                      id;
4368c2ecf20Sopenharmony_ci    struct snd_rawmidi           *rmidi;
4378c2ecf20Sopenharmony_ci    struct snd_rawmidi_substream *input;
4388c2ecf20Sopenharmony_ci    struct snd_rawmidi_substream *output;
4398c2ecf20Sopenharmony_ci    signed char		     istimer; /* timer in use */
4408c2ecf20Sopenharmony_ci    struct timer_list	     timer;
4418c2ecf20Sopenharmony_ci    spinlock_t               lock;
4428c2ecf20Sopenharmony_ci    int			     pending;
4438c2ecf20Sopenharmony_ci};
4448c2ecf20Sopenharmony_ci
4458c2ecf20Sopenharmony_cistruct hdsp {
4468c2ecf20Sopenharmony_ci	spinlock_t            lock;
4478c2ecf20Sopenharmony_ci	struct snd_pcm_substream *capture_substream;
4488c2ecf20Sopenharmony_ci	struct snd_pcm_substream *playback_substream;
4498c2ecf20Sopenharmony_ci        struct hdsp_midi      midi[2];
4508c2ecf20Sopenharmony_ci	struct work_struct    midi_work;
4518c2ecf20Sopenharmony_ci	int		      use_midi_work;
4528c2ecf20Sopenharmony_ci	int                   precise_ptr;
4538c2ecf20Sopenharmony_ci	u32                   control_register;	     /* cached value */
4548c2ecf20Sopenharmony_ci	u32                   control2_register;     /* cached value */
4558c2ecf20Sopenharmony_ci	u32                   creg_spdif;
4568c2ecf20Sopenharmony_ci	u32                   creg_spdif_stream;
4578c2ecf20Sopenharmony_ci	int                   clock_source_locked;
4588c2ecf20Sopenharmony_ci	char                 *card_name;	 /* digiface/multiface/rpm */
4598c2ecf20Sopenharmony_ci	enum HDSP_IO_Type     io_type;               /* ditto, but for code use */
4608c2ecf20Sopenharmony_ci        unsigned short        firmware_rev;
4618c2ecf20Sopenharmony_ci	unsigned short	      state;		     /* stores state bits */
4628c2ecf20Sopenharmony_ci	const struct firmware *firmware;
4638c2ecf20Sopenharmony_ci	u32                  *fw_uploaded;
4648c2ecf20Sopenharmony_ci	size_t                period_bytes; 	     /* guess what this is */
4658c2ecf20Sopenharmony_ci	unsigned char	      max_channels;
4668c2ecf20Sopenharmony_ci	unsigned char	      qs_in_channels;	     /* quad speed mode for H9632 */
4678c2ecf20Sopenharmony_ci	unsigned char         ds_in_channels;
4688c2ecf20Sopenharmony_ci	unsigned char         ss_in_channels;	    /* different for multiface/digiface */
4698c2ecf20Sopenharmony_ci	unsigned char	      qs_out_channels;
4708c2ecf20Sopenharmony_ci	unsigned char         ds_out_channels;
4718c2ecf20Sopenharmony_ci	unsigned char         ss_out_channels;
4728c2ecf20Sopenharmony_ci
4738c2ecf20Sopenharmony_ci	struct snd_dma_buffer capture_dma_buf;
4748c2ecf20Sopenharmony_ci	struct snd_dma_buffer playback_dma_buf;
4758c2ecf20Sopenharmony_ci	unsigned char        *capture_buffer;	    /* suitably aligned address */
4768c2ecf20Sopenharmony_ci	unsigned char        *playback_buffer;	    /* suitably aligned address */
4778c2ecf20Sopenharmony_ci
4788c2ecf20Sopenharmony_ci	pid_t                 capture_pid;
4798c2ecf20Sopenharmony_ci	pid_t                 playback_pid;
4808c2ecf20Sopenharmony_ci	int                   running;
4818c2ecf20Sopenharmony_ci	int                   system_sample_rate;
4828c2ecf20Sopenharmony_ci	const signed char    *channel_map;
4838c2ecf20Sopenharmony_ci	int                   dev;
4848c2ecf20Sopenharmony_ci	int                   irq;
4858c2ecf20Sopenharmony_ci	unsigned long         port;
4868c2ecf20Sopenharmony_ci        void __iomem         *iobase;
4878c2ecf20Sopenharmony_ci	struct snd_card *card;
4888c2ecf20Sopenharmony_ci	struct snd_pcm *pcm;
4898c2ecf20Sopenharmony_ci	struct snd_hwdep          *hwdep;
4908c2ecf20Sopenharmony_ci	struct pci_dev       *pci;
4918c2ecf20Sopenharmony_ci	struct snd_kcontrol *spdif_ctl;
4928c2ecf20Sopenharmony_ci        unsigned short        mixer_matrix[HDSP_MATRIX_MIXER_SIZE];
4938c2ecf20Sopenharmony_ci	unsigned int          dds_value; /* last value written to freq register */
4948c2ecf20Sopenharmony_ci};
4958c2ecf20Sopenharmony_ci
4968c2ecf20Sopenharmony_ci/* These tables map the ALSA channels 1..N to the channels that we
4978c2ecf20Sopenharmony_ci   need to use in order to find the relevant channel buffer. RME
4988c2ecf20Sopenharmony_ci   refer to this kind of mapping as between "the ADAT channel and
4998c2ecf20Sopenharmony_ci   the DMA channel." We index it using the logical audio channel,
5008c2ecf20Sopenharmony_ci   and the value is the DMA channel (i.e. channel buffer number)
5018c2ecf20Sopenharmony_ci   where the data for that channel can be read/written from/to.
5028c2ecf20Sopenharmony_ci*/
5038c2ecf20Sopenharmony_ci
5048c2ecf20Sopenharmony_cistatic const signed char channel_map_df_ss[HDSP_MAX_CHANNELS] = {
5058c2ecf20Sopenharmony_ci	0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17,
5068c2ecf20Sopenharmony_ci	18, 19, 20, 21, 22, 23, 24, 25
5078c2ecf20Sopenharmony_ci};
5088c2ecf20Sopenharmony_ci
5098c2ecf20Sopenharmony_cistatic const char channel_map_mf_ss[HDSP_MAX_CHANNELS] = { /* Multiface */
5108c2ecf20Sopenharmony_ci	/* Analog */
5118c2ecf20Sopenharmony_ci	0, 1, 2, 3, 4, 5, 6, 7,
5128c2ecf20Sopenharmony_ci	/* ADAT 2 */
5138c2ecf20Sopenharmony_ci	16, 17, 18, 19, 20, 21, 22, 23,
5148c2ecf20Sopenharmony_ci	/* SPDIF */
5158c2ecf20Sopenharmony_ci	24, 25,
5168c2ecf20Sopenharmony_ci	-1, -1, -1, -1, -1, -1, -1, -1
5178c2ecf20Sopenharmony_ci};
5188c2ecf20Sopenharmony_ci
5198c2ecf20Sopenharmony_cistatic const signed char channel_map_ds[HDSP_MAX_CHANNELS] = {
5208c2ecf20Sopenharmony_ci	/* ADAT channels are remapped */
5218c2ecf20Sopenharmony_ci	1, 3, 5, 7, 9, 11, 13, 15, 17, 19, 21, 23,
5228c2ecf20Sopenharmony_ci	/* channels 12 and 13 are S/PDIF */
5238c2ecf20Sopenharmony_ci	24, 25,
5248c2ecf20Sopenharmony_ci	/* others don't exist */
5258c2ecf20Sopenharmony_ci	-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1
5268c2ecf20Sopenharmony_ci};
5278c2ecf20Sopenharmony_ci
5288c2ecf20Sopenharmony_cistatic const signed char channel_map_H9632_ss[HDSP_MAX_CHANNELS] = {
5298c2ecf20Sopenharmony_ci	/* ADAT channels */
5308c2ecf20Sopenharmony_ci	0, 1, 2, 3, 4, 5, 6, 7,
5318c2ecf20Sopenharmony_ci	/* SPDIF */
5328c2ecf20Sopenharmony_ci	8, 9,
5338c2ecf20Sopenharmony_ci	/* Analog */
5348c2ecf20Sopenharmony_ci	10, 11,
5358c2ecf20Sopenharmony_ci	/* AO4S-192 and AI4S-192 extension boards */
5368c2ecf20Sopenharmony_ci	12, 13, 14, 15,
5378c2ecf20Sopenharmony_ci	/* others don't exist */
5388c2ecf20Sopenharmony_ci	-1, -1, -1, -1, -1, -1, -1, -1,
5398c2ecf20Sopenharmony_ci	-1, -1
5408c2ecf20Sopenharmony_ci};
5418c2ecf20Sopenharmony_ci
5428c2ecf20Sopenharmony_cistatic const signed char channel_map_H9632_ds[HDSP_MAX_CHANNELS] = {
5438c2ecf20Sopenharmony_ci	/* ADAT */
5448c2ecf20Sopenharmony_ci	1, 3, 5, 7,
5458c2ecf20Sopenharmony_ci	/* SPDIF */
5468c2ecf20Sopenharmony_ci	8, 9,
5478c2ecf20Sopenharmony_ci	/* Analog */
5488c2ecf20Sopenharmony_ci	10, 11,
5498c2ecf20Sopenharmony_ci	/* AO4S-192 and AI4S-192 extension boards */
5508c2ecf20Sopenharmony_ci	12, 13, 14, 15,
5518c2ecf20Sopenharmony_ci	/* others don't exist */
5528c2ecf20Sopenharmony_ci	-1, -1, -1, -1, -1, -1, -1, -1,
5538c2ecf20Sopenharmony_ci	-1, -1, -1, -1, -1, -1
5548c2ecf20Sopenharmony_ci};
5558c2ecf20Sopenharmony_ci
5568c2ecf20Sopenharmony_cistatic const signed char channel_map_H9632_qs[HDSP_MAX_CHANNELS] = {
5578c2ecf20Sopenharmony_ci	/* ADAT is disabled in this mode */
5588c2ecf20Sopenharmony_ci	/* SPDIF */
5598c2ecf20Sopenharmony_ci	8, 9,
5608c2ecf20Sopenharmony_ci	/* Analog */
5618c2ecf20Sopenharmony_ci	10, 11,
5628c2ecf20Sopenharmony_ci	/* AO4S-192 and AI4S-192 extension boards */
5638c2ecf20Sopenharmony_ci	12, 13, 14, 15,
5648c2ecf20Sopenharmony_ci	/* others don't exist */
5658c2ecf20Sopenharmony_ci	-1, -1, -1, -1, -1, -1, -1, -1,
5668c2ecf20Sopenharmony_ci	-1, -1, -1, -1, -1, -1, -1, -1,
5678c2ecf20Sopenharmony_ci	-1, -1
5688c2ecf20Sopenharmony_ci};
5698c2ecf20Sopenharmony_ci
5708c2ecf20Sopenharmony_cistatic int snd_hammerfall_get_buffer(struct pci_dev *pci, struct snd_dma_buffer *dmab, size_t size)
5718c2ecf20Sopenharmony_ci{
5728c2ecf20Sopenharmony_ci	return snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, &pci->dev, size, dmab);
5738c2ecf20Sopenharmony_ci}
5748c2ecf20Sopenharmony_ci
5758c2ecf20Sopenharmony_cistatic void snd_hammerfall_free_buffer(struct snd_dma_buffer *dmab, struct pci_dev *pci)
5768c2ecf20Sopenharmony_ci{
5778c2ecf20Sopenharmony_ci	if (dmab->area)
5788c2ecf20Sopenharmony_ci		snd_dma_free_pages(dmab);
5798c2ecf20Sopenharmony_ci}
5808c2ecf20Sopenharmony_ci
5818c2ecf20Sopenharmony_ci
5828c2ecf20Sopenharmony_cistatic const struct pci_device_id snd_hdsp_ids[] = {
5838c2ecf20Sopenharmony_ci	{
5848c2ecf20Sopenharmony_ci		.vendor = PCI_VENDOR_ID_XILINX,
5858c2ecf20Sopenharmony_ci		.device = PCI_DEVICE_ID_XILINX_HAMMERFALL_DSP,
5868c2ecf20Sopenharmony_ci		.subvendor = PCI_ANY_ID,
5878c2ecf20Sopenharmony_ci		.subdevice = PCI_ANY_ID,
5888c2ecf20Sopenharmony_ci	}, /* RME Hammerfall-DSP */
5898c2ecf20Sopenharmony_ci	{ 0, },
5908c2ecf20Sopenharmony_ci};
5918c2ecf20Sopenharmony_ci
5928c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(pci, snd_hdsp_ids);
5938c2ecf20Sopenharmony_ci
5948c2ecf20Sopenharmony_ci/* prototypes */
5958c2ecf20Sopenharmony_cistatic int snd_hdsp_create_alsa_devices(struct snd_card *card, struct hdsp *hdsp);
5968c2ecf20Sopenharmony_cistatic int snd_hdsp_create_pcm(struct snd_card *card, struct hdsp *hdsp);
5978c2ecf20Sopenharmony_cistatic int snd_hdsp_enable_io (struct hdsp *hdsp);
5988c2ecf20Sopenharmony_cistatic void snd_hdsp_initialize_midi_flush (struct hdsp *hdsp);
5998c2ecf20Sopenharmony_cistatic void snd_hdsp_initialize_channels (struct hdsp *hdsp);
6008c2ecf20Sopenharmony_cistatic int hdsp_fifo_wait(struct hdsp *hdsp, int count, int timeout);
6018c2ecf20Sopenharmony_cistatic int hdsp_autosync_ref(struct hdsp *hdsp);
6028c2ecf20Sopenharmony_cistatic int snd_hdsp_set_defaults(struct hdsp *hdsp);
6038c2ecf20Sopenharmony_cistatic void snd_hdsp_9652_enable_mixer (struct hdsp *hdsp);
6048c2ecf20Sopenharmony_ci
6058c2ecf20Sopenharmony_cistatic int hdsp_playback_to_output_key (struct hdsp *hdsp, int in, int out)
6068c2ecf20Sopenharmony_ci{
6078c2ecf20Sopenharmony_ci	switch (hdsp->io_type) {
6088c2ecf20Sopenharmony_ci	case Multiface:
6098c2ecf20Sopenharmony_ci	case Digiface:
6108c2ecf20Sopenharmony_ci	case RPM:
6118c2ecf20Sopenharmony_ci	default:
6128c2ecf20Sopenharmony_ci		if (hdsp->firmware_rev == 0xa)
6138c2ecf20Sopenharmony_ci			return (64 * out) + (32 + (in));
6148c2ecf20Sopenharmony_ci		else
6158c2ecf20Sopenharmony_ci			return (52 * out) + (26 + (in));
6168c2ecf20Sopenharmony_ci	case H9632:
6178c2ecf20Sopenharmony_ci		return (32 * out) + (16 + (in));
6188c2ecf20Sopenharmony_ci	case H9652:
6198c2ecf20Sopenharmony_ci		return (52 * out) + (26 + (in));
6208c2ecf20Sopenharmony_ci	}
6218c2ecf20Sopenharmony_ci}
6228c2ecf20Sopenharmony_ci
6238c2ecf20Sopenharmony_cistatic int hdsp_input_to_output_key (struct hdsp *hdsp, int in, int out)
6248c2ecf20Sopenharmony_ci{
6258c2ecf20Sopenharmony_ci	switch (hdsp->io_type) {
6268c2ecf20Sopenharmony_ci	case Multiface:
6278c2ecf20Sopenharmony_ci	case Digiface:
6288c2ecf20Sopenharmony_ci	case RPM:
6298c2ecf20Sopenharmony_ci	default:
6308c2ecf20Sopenharmony_ci		if (hdsp->firmware_rev == 0xa)
6318c2ecf20Sopenharmony_ci			return (64 * out) + in;
6328c2ecf20Sopenharmony_ci		else
6338c2ecf20Sopenharmony_ci			return (52 * out) + in;
6348c2ecf20Sopenharmony_ci	case H9632:
6358c2ecf20Sopenharmony_ci		return (32 * out) + in;
6368c2ecf20Sopenharmony_ci	case H9652:
6378c2ecf20Sopenharmony_ci		return (52 * out) + in;
6388c2ecf20Sopenharmony_ci	}
6398c2ecf20Sopenharmony_ci}
6408c2ecf20Sopenharmony_ci
6418c2ecf20Sopenharmony_cistatic void hdsp_write(struct hdsp *hdsp, int reg, int val)
6428c2ecf20Sopenharmony_ci{
6438c2ecf20Sopenharmony_ci	writel(val, hdsp->iobase + reg);
6448c2ecf20Sopenharmony_ci}
6458c2ecf20Sopenharmony_ci
6468c2ecf20Sopenharmony_cistatic unsigned int hdsp_read(struct hdsp *hdsp, int reg)
6478c2ecf20Sopenharmony_ci{
6488c2ecf20Sopenharmony_ci	return readl (hdsp->iobase + reg);
6498c2ecf20Sopenharmony_ci}
6508c2ecf20Sopenharmony_ci
6518c2ecf20Sopenharmony_cistatic int hdsp_check_for_iobox (struct hdsp *hdsp)
6528c2ecf20Sopenharmony_ci{
6538c2ecf20Sopenharmony_ci	int i;
6548c2ecf20Sopenharmony_ci
6558c2ecf20Sopenharmony_ci	if (hdsp->io_type == H9652 || hdsp->io_type == H9632) return 0;
6568c2ecf20Sopenharmony_ci	for (i = 0; i < 500; i++) {
6578c2ecf20Sopenharmony_ci		if (0 == (hdsp_read(hdsp, HDSP_statusRegister) &
6588c2ecf20Sopenharmony_ci					HDSP_ConfigError)) {
6598c2ecf20Sopenharmony_ci			if (i) {
6608c2ecf20Sopenharmony_ci				dev_dbg(hdsp->card->dev,
6618c2ecf20Sopenharmony_ci					"IO box found after %d ms\n",
6628c2ecf20Sopenharmony_ci						(20 * i));
6638c2ecf20Sopenharmony_ci			}
6648c2ecf20Sopenharmony_ci			return 0;
6658c2ecf20Sopenharmony_ci		}
6668c2ecf20Sopenharmony_ci		msleep(20);
6678c2ecf20Sopenharmony_ci	}
6688c2ecf20Sopenharmony_ci	dev_err(hdsp->card->dev, "no IO box connected!\n");
6698c2ecf20Sopenharmony_ci	hdsp->state &= ~HDSP_FirmwareLoaded;
6708c2ecf20Sopenharmony_ci	return -EIO;
6718c2ecf20Sopenharmony_ci}
6728c2ecf20Sopenharmony_ci
6738c2ecf20Sopenharmony_cistatic int hdsp_wait_for_iobox(struct hdsp *hdsp, unsigned int loops,
6748c2ecf20Sopenharmony_ci			       unsigned int delay)
6758c2ecf20Sopenharmony_ci{
6768c2ecf20Sopenharmony_ci	unsigned int i;
6778c2ecf20Sopenharmony_ci
6788c2ecf20Sopenharmony_ci	if (hdsp->io_type == H9652 || hdsp->io_type == H9632)
6798c2ecf20Sopenharmony_ci		return 0;
6808c2ecf20Sopenharmony_ci
6818c2ecf20Sopenharmony_ci	for (i = 0; i != loops; ++i) {
6828c2ecf20Sopenharmony_ci		if (hdsp_read(hdsp, HDSP_statusRegister) & HDSP_ConfigError)
6838c2ecf20Sopenharmony_ci			msleep(delay);
6848c2ecf20Sopenharmony_ci		else {
6858c2ecf20Sopenharmony_ci			dev_dbg(hdsp->card->dev, "iobox found after %ums!\n",
6868c2ecf20Sopenharmony_ci				   i * delay);
6878c2ecf20Sopenharmony_ci			return 0;
6888c2ecf20Sopenharmony_ci		}
6898c2ecf20Sopenharmony_ci	}
6908c2ecf20Sopenharmony_ci
6918c2ecf20Sopenharmony_ci	dev_info(hdsp->card->dev, "no IO box connected!\n");
6928c2ecf20Sopenharmony_ci	hdsp->state &= ~HDSP_FirmwareLoaded;
6938c2ecf20Sopenharmony_ci	return -EIO;
6948c2ecf20Sopenharmony_ci}
6958c2ecf20Sopenharmony_ci
6968c2ecf20Sopenharmony_cistatic int snd_hdsp_load_firmware_from_cache(struct hdsp *hdsp) {
6978c2ecf20Sopenharmony_ci
6988c2ecf20Sopenharmony_ci	int i;
6998c2ecf20Sopenharmony_ci	unsigned long flags;
7008c2ecf20Sopenharmony_ci	const u32 *cache;
7018c2ecf20Sopenharmony_ci
7028c2ecf20Sopenharmony_ci	if (hdsp->fw_uploaded)
7038c2ecf20Sopenharmony_ci		cache = hdsp->fw_uploaded;
7048c2ecf20Sopenharmony_ci	else {
7058c2ecf20Sopenharmony_ci		if (!hdsp->firmware)
7068c2ecf20Sopenharmony_ci			return -ENODEV;
7078c2ecf20Sopenharmony_ci		cache = (u32 *)hdsp->firmware->data;
7088c2ecf20Sopenharmony_ci		if (!cache)
7098c2ecf20Sopenharmony_ci			return -ENODEV;
7108c2ecf20Sopenharmony_ci	}
7118c2ecf20Sopenharmony_ci
7128c2ecf20Sopenharmony_ci	if ((hdsp_read (hdsp, HDSP_statusRegister) & HDSP_DllError) != 0) {
7138c2ecf20Sopenharmony_ci
7148c2ecf20Sopenharmony_ci		dev_info(hdsp->card->dev, "loading firmware\n");
7158c2ecf20Sopenharmony_ci
7168c2ecf20Sopenharmony_ci		hdsp_write (hdsp, HDSP_control2Reg, HDSP_S_PROGRAM);
7178c2ecf20Sopenharmony_ci		hdsp_write (hdsp, HDSP_fifoData, 0);
7188c2ecf20Sopenharmony_ci
7198c2ecf20Sopenharmony_ci		if (hdsp_fifo_wait (hdsp, 0, HDSP_LONG_WAIT)) {
7208c2ecf20Sopenharmony_ci			dev_info(hdsp->card->dev,
7218c2ecf20Sopenharmony_ci				 "timeout waiting for download preparation\n");
7228c2ecf20Sopenharmony_ci			hdsp_write(hdsp, HDSP_control2Reg, HDSP_S200);
7238c2ecf20Sopenharmony_ci			return -EIO;
7248c2ecf20Sopenharmony_ci		}
7258c2ecf20Sopenharmony_ci
7268c2ecf20Sopenharmony_ci		hdsp_write (hdsp, HDSP_control2Reg, HDSP_S_LOAD);
7278c2ecf20Sopenharmony_ci
7288c2ecf20Sopenharmony_ci		for (i = 0; i < HDSP_FIRMWARE_SIZE / 4; ++i) {
7298c2ecf20Sopenharmony_ci			hdsp_write(hdsp, HDSP_fifoData, cache[i]);
7308c2ecf20Sopenharmony_ci			if (hdsp_fifo_wait (hdsp, 127, HDSP_LONG_WAIT)) {
7318c2ecf20Sopenharmony_ci				dev_info(hdsp->card->dev,
7328c2ecf20Sopenharmony_ci					 "timeout during firmware loading\n");
7338c2ecf20Sopenharmony_ci				hdsp_write(hdsp, HDSP_control2Reg, HDSP_S200);
7348c2ecf20Sopenharmony_ci				return -EIO;
7358c2ecf20Sopenharmony_ci			}
7368c2ecf20Sopenharmony_ci		}
7378c2ecf20Sopenharmony_ci
7388c2ecf20Sopenharmony_ci		hdsp_fifo_wait(hdsp, 3, HDSP_LONG_WAIT);
7398c2ecf20Sopenharmony_ci		hdsp_write(hdsp, HDSP_control2Reg, HDSP_S200);
7408c2ecf20Sopenharmony_ci
7418c2ecf20Sopenharmony_ci		ssleep(3);
7428c2ecf20Sopenharmony_ci#ifdef SNDRV_BIG_ENDIAN
7438c2ecf20Sopenharmony_ci		hdsp->control2_register = HDSP_BIGENDIAN_MODE;
7448c2ecf20Sopenharmony_ci#else
7458c2ecf20Sopenharmony_ci		hdsp->control2_register = 0;
7468c2ecf20Sopenharmony_ci#endif
7478c2ecf20Sopenharmony_ci		hdsp_write (hdsp, HDSP_control2Reg, hdsp->control2_register);
7488c2ecf20Sopenharmony_ci		dev_info(hdsp->card->dev, "finished firmware loading\n");
7498c2ecf20Sopenharmony_ci
7508c2ecf20Sopenharmony_ci	}
7518c2ecf20Sopenharmony_ci	if (hdsp->state & HDSP_InitializationComplete) {
7528c2ecf20Sopenharmony_ci		dev_info(hdsp->card->dev,
7538c2ecf20Sopenharmony_ci			 "firmware loaded from cache, restoring defaults\n");
7548c2ecf20Sopenharmony_ci		spin_lock_irqsave(&hdsp->lock, flags);
7558c2ecf20Sopenharmony_ci		snd_hdsp_set_defaults(hdsp);
7568c2ecf20Sopenharmony_ci		spin_unlock_irqrestore(&hdsp->lock, flags);
7578c2ecf20Sopenharmony_ci	}
7588c2ecf20Sopenharmony_ci
7598c2ecf20Sopenharmony_ci	hdsp->state |= HDSP_FirmwareLoaded;
7608c2ecf20Sopenharmony_ci
7618c2ecf20Sopenharmony_ci	return 0;
7628c2ecf20Sopenharmony_ci}
7638c2ecf20Sopenharmony_ci
7648c2ecf20Sopenharmony_cistatic int hdsp_get_iobox_version (struct hdsp *hdsp)
7658c2ecf20Sopenharmony_ci{
7668c2ecf20Sopenharmony_ci	if ((hdsp_read (hdsp, HDSP_statusRegister) & HDSP_DllError) != 0) {
7678c2ecf20Sopenharmony_ci
7688c2ecf20Sopenharmony_ci		hdsp_write(hdsp, HDSP_control2Reg, HDSP_S_LOAD);
7698c2ecf20Sopenharmony_ci		hdsp_write(hdsp, HDSP_fifoData, 0);
7708c2ecf20Sopenharmony_ci
7718c2ecf20Sopenharmony_ci		if (hdsp_fifo_wait(hdsp, 0, HDSP_SHORT_WAIT) < 0) {
7728c2ecf20Sopenharmony_ci			hdsp_write(hdsp, HDSP_control2Reg, HDSP_S300);
7738c2ecf20Sopenharmony_ci			hdsp_write(hdsp, HDSP_control2Reg, HDSP_S_LOAD);
7748c2ecf20Sopenharmony_ci		}
7758c2ecf20Sopenharmony_ci
7768c2ecf20Sopenharmony_ci		hdsp_write(hdsp, HDSP_control2Reg, HDSP_S200 | HDSP_PROGRAM);
7778c2ecf20Sopenharmony_ci		hdsp_write (hdsp, HDSP_fifoData, 0);
7788c2ecf20Sopenharmony_ci		if (hdsp_fifo_wait(hdsp, 0, HDSP_SHORT_WAIT) < 0)
7798c2ecf20Sopenharmony_ci			goto set_multi;
7808c2ecf20Sopenharmony_ci
7818c2ecf20Sopenharmony_ci		hdsp_write(hdsp, HDSP_control2Reg, HDSP_S_LOAD);
7828c2ecf20Sopenharmony_ci		hdsp_write(hdsp, HDSP_fifoData, 0);
7838c2ecf20Sopenharmony_ci		if (hdsp_fifo_wait(hdsp, 0, HDSP_SHORT_WAIT) == 0) {
7848c2ecf20Sopenharmony_ci			hdsp->io_type = Digiface;
7858c2ecf20Sopenharmony_ci			dev_info(hdsp->card->dev, "Digiface found\n");
7868c2ecf20Sopenharmony_ci			return 0;
7878c2ecf20Sopenharmony_ci		}
7888c2ecf20Sopenharmony_ci
7898c2ecf20Sopenharmony_ci		hdsp_write(hdsp, HDSP_control2Reg, HDSP_S300);
7908c2ecf20Sopenharmony_ci		hdsp_write(hdsp, HDSP_control2Reg, HDSP_S_LOAD);
7918c2ecf20Sopenharmony_ci		hdsp_write(hdsp, HDSP_fifoData, 0);
7928c2ecf20Sopenharmony_ci		if (hdsp_fifo_wait(hdsp, 0, HDSP_SHORT_WAIT) == 0)
7938c2ecf20Sopenharmony_ci			goto set_multi;
7948c2ecf20Sopenharmony_ci
7958c2ecf20Sopenharmony_ci		hdsp_write(hdsp, HDSP_control2Reg, HDSP_S300);
7968c2ecf20Sopenharmony_ci		hdsp_write(hdsp, HDSP_control2Reg, HDSP_S_LOAD);
7978c2ecf20Sopenharmony_ci		hdsp_write(hdsp, HDSP_fifoData, 0);
7988c2ecf20Sopenharmony_ci		if (hdsp_fifo_wait(hdsp, 0, HDSP_SHORT_WAIT) < 0)
7998c2ecf20Sopenharmony_ci			goto set_multi;
8008c2ecf20Sopenharmony_ci
8018c2ecf20Sopenharmony_ci		hdsp->io_type = RPM;
8028c2ecf20Sopenharmony_ci		dev_info(hdsp->card->dev, "RPM found\n");
8038c2ecf20Sopenharmony_ci		return 0;
8048c2ecf20Sopenharmony_ci	} else {
8058c2ecf20Sopenharmony_ci		/* firmware was already loaded, get iobox type */
8068c2ecf20Sopenharmony_ci		if (hdsp_read(hdsp, HDSP_status2Register) & HDSP_version2)
8078c2ecf20Sopenharmony_ci			hdsp->io_type = RPM;
8088c2ecf20Sopenharmony_ci		else if (hdsp_read(hdsp, HDSP_status2Register) & HDSP_version1)
8098c2ecf20Sopenharmony_ci			hdsp->io_type = Multiface;
8108c2ecf20Sopenharmony_ci		else
8118c2ecf20Sopenharmony_ci			hdsp->io_type = Digiface;
8128c2ecf20Sopenharmony_ci	}
8138c2ecf20Sopenharmony_ci	return 0;
8148c2ecf20Sopenharmony_ci
8158c2ecf20Sopenharmony_ciset_multi:
8168c2ecf20Sopenharmony_ci	hdsp->io_type = Multiface;
8178c2ecf20Sopenharmony_ci	dev_info(hdsp->card->dev, "Multiface found\n");
8188c2ecf20Sopenharmony_ci	return 0;
8198c2ecf20Sopenharmony_ci}
8208c2ecf20Sopenharmony_ci
8218c2ecf20Sopenharmony_ci
8228c2ecf20Sopenharmony_cistatic int hdsp_request_fw_loader(struct hdsp *hdsp);
8238c2ecf20Sopenharmony_ci
8248c2ecf20Sopenharmony_cistatic int hdsp_check_for_firmware (struct hdsp *hdsp, int load_on_demand)
8258c2ecf20Sopenharmony_ci{
8268c2ecf20Sopenharmony_ci	if (hdsp->io_type == H9652 || hdsp->io_type == H9632)
8278c2ecf20Sopenharmony_ci		return 0;
8288c2ecf20Sopenharmony_ci	if ((hdsp_read (hdsp, HDSP_statusRegister) & HDSP_DllError) != 0) {
8298c2ecf20Sopenharmony_ci		hdsp->state &= ~HDSP_FirmwareLoaded;
8308c2ecf20Sopenharmony_ci		if (! load_on_demand)
8318c2ecf20Sopenharmony_ci			return -EIO;
8328c2ecf20Sopenharmony_ci		dev_err(hdsp->card->dev, "firmware not present.\n");
8338c2ecf20Sopenharmony_ci		/* try to load firmware */
8348c2ecf20Sopenharmony_ci		if (! (hdsp->state & HDSP_FirmwareCached)) {
8358c2ecf20Sopenharmony_ci			if (! hdsp_request_fw_loader(hdsp))
8368c2ecf20Sopenharmony_ci				return 0;
8378c2ecf20Sopenharmony_ci			dev_err(hdsp->card->dev,
8388c2ecf20Sopenharmony_ci				   "No firmware loaded nor cached, please upload firmware.\n");
8398c2ecf20Sopenharmony_ci			return -EIO;
8408c2ecf20Sopenharmony_ci		}
8418c2ecf20Sopenharmony_ci		if (snd_hdsp_load_firmware_from_cache(hdsp) != 0) {
8428c2ecf20Sopenharmony_ci			dev_err(hdsp->card->dev,
8438c2ecf20Sopenharmony_ci				   "Firmware loading from cache failed, please upload manually.\n");
8448c2ecf20Sopenharmony_ci			return -EIO;
8458c2ecf20Sopenharmony_ci		}
8468c2ecf20Sopenharmony_ci	}
8478c2ecf20Sopenharmony_ci	return 0;
8488c2ecf20Sopenharmony_ci}
8498c2ecf20Sopenharmony_ci
8508c2ecf20Sopenharmony_ci
8518c2ecf20Sopenharmony_cistatic int hdsp_fifo_wait(struct hdsp *hdsp, int count, int timeout)
8528c2ecf20Sopenharmony_ci{
8538c2ecf20Sopenharmony_ci	int i;
8548c2ecf20Sopenharmony_ci
8558c2ecf20Sopenharmony_ci	/* the fifoStatus registers reports on how many words
8568c2ecf20Sopenharmony_ci	   are available in the command FIFO.
8578c2ecf20Sopenharmony_ci	*/
8588c2ecf20Sopenharmony_ci
8598c2ecf20Sopenharmony_ci	for (i = 0; i < timeout; i++) {
8608c2ecf20Sopenharmony_ci
8618c2ecf20Sopenharmony_ci		if ((int)(hdsp_read (hdsp, HDSP_fifoStatus) & 0xff) <= count)
8628c2ecf20Sopenharmony_ci			return 0;
8638c2ecf20Sopenharmony_ci
8648c2ecf20Sopenharmony_ci		/* not very friendly, but we only do this during a firmware
8658c2ecf20Sopenharmony_ci		   load and changing the mixer, so we just put up with it.
8668c2ecf20Sopenharmony_ci		*/
8678c2ecf20Sopenharmony_ci
8688c2ecf20Sopenharmony_ci		udelay (100);
8698c2ecf20Sopenharmony_ci	}
8708c2ecf20Sopenharmony_ci
8718c2ecf20Sopenharmony_ci	dev_warn(hdsp->card->dev,
8728c2ecf20Sopenharmony_ci		 "wait for FIFO status <= %d failed after %d iterations\n",
8738c2ecf20Sopenharmony_ci		    count, timeout);
8748c2ecf20Sopenharmony_ci	return -1;
8758c2ecf20Sopenharmony_ci}
8768c2ecf20Sopenharmony_ci
8778c2ecf20Sopenharmony_cistatic int hdsp_read_gain (struct hdsp *hdsp, unsigned int addr)
8788c2ecf20Sopenharmony_ci{
8798c2ecf20Sopenharmony_ci	if (addr >= HDSP_MATRIX_MIXER_SIZE)
8808c2ecf20Sopenharmony_ci		return 0;
8818c2ecf20Sopenharmony_ci
8828c2ecf20Sopenharmony_ci	return hdsp->mixer_matrix[addr];
8838c2ecf20Sopenharmony_ci}
8848c2ecf20Sopenharmony_ci
8858c2ecf20Sopenharmony_cistatic int hdsp_write_gain(struct hdsp *hdsp, unsigned int addr, unsigned short data)
8868c2ecf20Sopenharmony_ci{
8878c2ecf20Sopenharmony_ci	unsigned int ad;
8888c2ecf20Sopenharmony_ci
8898c2ecf20Sopenharmony_ci	if (addr >= HDSP_MATRIX_MIXER_SIZE)
8908c2ecf20Sopenharmony_ci		return -1;
8918c2ecf20Sopenharmony_ci
8928c2ecf20Sopenharmony_ci	if (hdsp->io_type == H9652 || hdsp->io_type == H9632) {
8938c2ecf20Sopenharmony_ci
8948c2ecf20Sopenharmony_ci		/* from martin bjornsen:
8958c2ecf20Sopenharmony_ci
8968c2ecf20Sopenharmony_ci		   "You can only write dwords to the
8978c2ecf20Sopenharmony_ci		   mixer memory which contain two
8988c2ecf20Sopenharmony_ci		   mixer values in the low and high
8998c2ecf20Sopenharmony_ci		   word. So if you want to change
9008c2ecf20Sopenharmony_ci		   value 0 you have to read value 1
9018c2ecf20Sopenharmony_ci		   from the cache and write both to
9028c2ecf20Sopenharmony_ci		   the first dword in the mixer
9038c2ecf20Sopenharmony_ci		   memory."
9048c2ecf20Sopenharmony_ci		*/
9058c2ecf20Sopenharmony_ci
9068c2ecf20Sopenharmony_ci		if (hdsp->io_type == H9632 && addr >= 512)
9078c2ecf20Sopenharmony_ci			return 0;
9088c2ecf20Sopenharmony_ci
9098c2ecf20Sopenharmony_ci		if (hdsp->io_type == H9652 && addr >= 1352)
9108c2ecf20Sopenharmony_ci			return 0;
9118c2ecf20Sopenharmony_ci
9128c2ecf20Sopenharmony_ci		hdsp->mixer_matrix[addr] = data;
9138c2ecf20Sopenharmony_ci
9148c2ecf20Sopenharmony_ci
9158c2ecf20Sopenharmony_ci		/* `addr' addresses a 16-bit wide address, but
9168c2ecf20Sopenharmony_ci		   the address space accessed via hdsp_write
9178c2ecf20Sopenharmony_ci		   uses byte offsets. put another way, addr
9188c2ecf20Sopenharmony_ci		   varies from 0 to 1351, but to access the
9198c2ecf20Sopenharmony_ci		   corresponding memory location, we need
9208c2ecf20Sopenharmony_ci		   to access 0 to 2703 ...
9218c2ecf20Sopenharmony_ci		*/
9228c2ecf20Sopenharmony_ci		ad = addr/2;
9238c2ecf20Sopenharmony_ci
9248c2ecf20Sopenharmony_ci		hdsp_write (hdsp, 4096 + (ad*4),
9258c2ecf20Sopenharmony_ci			    (hdsp->mixer_matrix[(addr&0x7fe)+1] << 16) +
9268c2ecf20Sopenharmony_ci			    hdsp->mixer_matrix[addr&0x7fe]);
9278c2ecf20Sopenharmony_ci
9288c2ecf20Sopenharmony_ci		return 0;
9298c2ecf20Sopenharmony_ci
9308c2ecf20Sopenharmony_ci	} else {
9318c2ecf20Sopenharmony_ci
9328c2ecf20Sopenharmony_ci		ad = (addr << 16) + data;
9338c2ecf20Sopenharmony_ci
9348c2ecf20Sopenharmony_ci		if (hdsp_fifo_wait(hdsp, 127, HDSP_LONG_WAIT))
9358c2ecf20Sopenharmony_ci			return -1;
9368c2ecf20Sopenharmony_ci
9378c2ecf20Sopenharmony_ci		hdsp_write (hdsp, HDSP_fifoData, ad);
9388c2ecf20Sopenharmony_ci		hdsp->mixer_matrix[addr] = data;
9398c2ecf20Sopenharmony_ci
9408c2ecf20Sopenharmony_ci	}
9418c2ecf20Sopenharmony_ci
9428c2ecf20Sopenharmony_ci	return 0;
9438c2ecf20Sopenharmony_ci}
9448c2ecf20Sopenharmony_ci
9458c2ecf20Sopenharmony_cistatic int snd_hdsp_use_is_exclusive(struct hdsp *hdsp)
9468c2ecf20Sopenharmony_ci{
9478c2ecf20Sopenharmony_ci	unsigned long flags;
9488c2ecf20Sopenharmony_ci	int ret = 1;
9498c2ecf20Sopenharmony_ci
9508c2ecf20Sopenharmony_ci	spin_lock_irqsave(&hdsp->lock, flags);
9518c2ecf20Sopenharmony_ci	if ((hdsp->playback_pid != hdsp->capture_pid) &&
9528c2ecf20Sopenharmony_ci	    (hdsp->playback_pid >= 0) && (hdsp->capture_pid >= 0))
9538c2ecf20Sopenharmony_ci		ret = 0;
9548c2ecf20Sopenharmony_ci	spin_unlock_irqrestore(&hdsp->lock, flags);
9558c2ecf20Sopenharmony_ci	return ret;
9568c2ecf20Sopenharmony_ci}
9578c2ecf20Sopenharmony_ci
9588c2ecf20Sopenharmony_cistatic int hdsp_spdif_sample_rate(struct hdsp *hdsp)
9598c2ecf20Sopenharmony_ci{
9608c2ecf20Sopenharmony_ci	unsigned int status = hdsp_read(hdsp, HDSP_statusRegister);
9618c2ecf20Sopenharmony_ci	unsigned int rate_bits = (status & HDSP_spdifFrequencyMask);
9628c2ecf20Sopenharmony_ci
9638c2ecf20Sopenharmony_ci	/* For the 9632, the mask is different */
9648c2ecf20Sopenharmony_ci	if (hdsp->io_type == H9632)
9658c2ecf20Sopenharmony_ci		 rate_bits = (status & HDSP_spdifFrequencyMask_9632);
9668c2ecf20Sopenharmony_ci
9678c2ecf20Sopenharmony_ci	if (status & HDSP_SPDIFErrorFlag)
9688c2ecf20Sopenharmony_ci		return 0;
9698c2ecf20Sopenharmony_ci
9708c2ecf20Sopenharmony_ci	switch (rate_bits) {
9718c2ecf20Sopenharmony_ci	case HDSP_spdifFrequency32KHz: return 32000;
9728c2ecf20Sopenharmony_ci	case HDSP_spdifFrequency44_1KHz: return 44100;
9738c2ecf20Sopenharmony_ci	case HDSP_spdifFrequency48KHz: return 48000;
9748c2ecf20Sopenharmony_ci	case HDSP_spdifFrequency64KHz: return 64000;
9758c2ecf20Sopenharmony_ci	case HDSP_spdifFrequency88_2KHz: return 88200;
9768c2ecf20Sopenharmony_ci	case HDSP_spdifFrequency96KHz: return 96000;
9778c2ecf20Sopenharmony_ci	case HDSP_spdifFrequency128KHz:
9788c2ecf20Sopenharmony_ci		if (hdsp->io_type == H9632) return 128000;
9798c2ecf20Sopenharmony_ci		break;
9808c2ecf20Sopenharmony_ci	case HDSP_spdifFrequency176_4KHz:
9818c2ecf20Sopenharmony_ci		if (hdsp->io_type == H9632) return 176400;
9828c2ecf20Sopenharmony_ci		break;
9838c2ecf20Sopenharmony_ci	case HDSP_spdifFrequency192KHz:
9848c2ecf20Sopenharmony_ci		if (hdsp->io_type == H9632) return 192000;
9858c2ecf20Sopenharmony_ci		break;
9868c2ecf20Sopenharmony_ci	default:
9878c2ecf20Sopenharmony_ci		break;
9888c2ecf20Sopenharmony_ci	}
9898c2ecf20Sopenharmony_ci	dev_warn(hdsp->card->dev,
9908c2ecf20Sopenharmony_ci		 "unknown spdif frequency status; bits = 0x%x, status = 0x%x\n",
9918c2ecf20Sopenharmony_ci		 rate_bits, status);
9928c2ecf20Sopenharmony_ci	return 0;
9938c2ecf20Sopenharmony_ci}
9948c2ecf20Sopenharmony_ci
9958c2ecf20Sopenharmony_cistatic int hdsp_external_sample_rate(struct hdsp *hdsp)
9968c2ecf20Sopenharmony_ci{
9978c2ecf20Sopenharmony_ci	unsigned int status2 = hdsp_read(hdsp, HDSP_status2Register);
9988c2ecf20Sopenharmony_ci	unsigned int rate_bits = status2 & HDSP_systemFrequencyMask;
9998c2ecf20Sopenharmony_ci
10008c2ecf20Sopenharmony_ci	/* For the 9632 card, there seems to be no bit for indicating external
10018c2ecf20Sopenharmony_ci	 * sample rate greater than 96kHz. The card reports the corresponding
10028c2ecf20Sopenharmony_ci	 * single speed. So the best means seems to get spdif rate when
10038c2ecf20Sopenharmony_ci	 * autosync reference is spdif */
10048c2ecf20Sopenharmony_ci	if (hdsp->io_type == H9632 &&
10058c2ecf20Sopenharmony_ci	    hdsp_autosync_ref(hdsp) == HDSP_AUTOSYNC_FROM_SPDIF)
10068c2ecf20Sopenharmony_ci		 return hdsp_spdif_sample_rate(hdsp);
10078c2ecf20Sopenharmony_ci
10088c2ecf20Sopenharmony_ci	switch (rate_bits) {
10098c2ecf20Sopenharmony_ci	case HDSP_systemFrequency32:   return 32000;
10108c2ecf20Sopenharmony_ci	case HDSP_systemFrequency44_1: return 44100;
10118c2ecf20Sopenharmony_ci	case HDSP_systemFrequency48:   return 48000;
10128c2ecf20Sopenharmony_ci	case HDSP_systemFrequency64:   return 64000;
10138c2ecf20Sopenharmony_ci	case HDSP_systemFrequency88_2: return 88200;
10148c2ecf20Sopenharmony_ci	case HDSP_systemFrequency96:   return 96000;
10158c2ecf20Sopenharmony_ci	default:
10168c2ecf20Sopenharmony_ci		return 0;
10178c2ecf20Sopenharmony_ci	}
10188c2ecf20Sopenharmony_ci}
10198c2ecf20Sopenharmony_ci
10208c2ecf20Sopenharmony_cistatic void hdsp_compute_period_size(struct hdsp *hdsp)
10218c2ecf20Sopenharmony_ci{
10228c2ecf20Sopenharmony_ci	hdsp->period_bytes = 1 << ((hdsp_decode_latency(hdsp->control_register) + 8));
10238c2ecf20Sopenharmony_ci}
10248c2ecf20Sopenharmony_ci
10258c2ecf20Sopenharmony_cistatic snd_pcm_uframes_t hdsp_hw_pointer(struct hdsp *hdsp)
10268c2ecf20Sopenharmony_ci{
10278c2ecf20Sopenharmony_ci	int position;
10288c2ecf20Sopenharmony_ci
10298c2ecf20Sopenharmony_ci	position = hdsp_read(hdsp, HDSP_statusRegister);
10308c2ecf20Sopenharmony_ci
10318c2ecf20Sopenharmony_ci	if (!hdsp->precise_ptr)
10328c2ecf20Sopenharmony_ci		return (position & HDSP_BufferID) ? (hdsp->period_bytes / 4) : 0;
10338c2ecf20Sopenharmony_ci
10348c2ecf20Sopenharmony_ci	position &= HDSP_BufferPositionMask;
10358c2ecf20Sopenharmony_ci	position /= 4;
10368c2ecf20Sopenharmony_ci	position &= (hdsp->period_bytes/2) - 1;
10378c2ecf20Sopenharmony_ci	return position;
10388c2ecf20Sopenharmony_ci}
10398c2ecf20Sopenharmony_ci
10408c2ecf20Sopenharmony_cistatic void hdsp_reset_hw_pointer(struct hdsp *hdsp)
10418c2ecf20Sopenharmony_ci{
10428c2ecf20Sopenharmony_ci	hdsp_write (hdsp, HDSP_resetPointer, 0);
10438c2ecf20Sopenharmony_ci	if (hdsp->io_type == H9632 && hdsp->firmware_rev >= 152)
10448c2ecf20Sopenharmony_ci		/* HDSP_resetPointer = HDSP_freqReg, which is strange and
10458c2ecf20Sopenharmony_ci		 * requires (?) to write again DDS value after a reset pointer
10468c2ecf20Sopenharmony_ci		 * (at least, it works like this) */
10478c2ecf20Sopenharmony_ci		hdsp_write (hdsp, HDSP_freqReg, hdsp->dds_value);
10488c2ecf20Sopenharmony_ci}
10498c2ecf20Sopenharmony_ci
10508c2ecf20Sopenharmony_cistatic void hdsp_start_audio(struct hdsp *s)
10518c2ecf20Sopenharmony_ci{
10528c2ecf20Sopenharmony_ci	s->control_register |= (HDSP_AudioInterruptEnable | HDSP_Start);
10538c2ecf20Sopenharmony_ci	hdsp_write(s, HDSP_controlRegister, s->control_register);
10548c2ecf20Sopenharmony_ci}
10558c2ecf20Sopenharmony_ci
10568c2ecf20Sopenharmony_cistatic void hdsp_stop_audio(struct hdsp *s)
10578c2ecf20Sopenharmony_ci{
10588c2ecf20Sopenharmony_ci	s->control_register &= ~(HDSP_Start | HDSP_AudioInterruptEnable);
10598c2ecf20Sopenharmony_ci	hdsp_write(s, HDSP_controlRegister, s->control_register);
10608c2ecf20Sopenharmony_ci}
10618c2ecf20Sopenharmony_ci
10628c2ecf20Sopenharmony_cistatic void hdsp_silence_playback(struct hdsp *hdsp)
10638c2ecf20Sopenharmony_ci{
10648c2ecf20Sopenharmony_ci	memset(hdsp->playback_buffer, 0, HDSP_DMA_AREA_BYTES);
10658c2ecf20Sopenharmony_ci}
10668c2ecf20Sopenharmony_ci
10678c2ecf20Sopenharmony_cistatic int hdsp_set_interrupt_interval(struct hdsp *s, unsigned int frames)
10688c2ecf20Sopenharmony_ci{
10698c2ecf20Sopenharmony_ci	int n;
10708c2ecf20Sopenharmony_ci
10718c2ecf20Sopenharmony_ci	spin_lock_irq(&s->lock);
10728c2ecf20Sopenharmony_ci
10738c2ecf20Sopenharmony_ci	frames >>= 7;
10748c2ecf20Sopenharmony_ci	n = 0;
10758c2ecf20Sopenharmony_ci	while (frames) {
10768c2ecf20Sopenharmony_ci		n++;
10778c2ecf20Sopenharmony_ci		frames >>= 1;
10788c2ecf20Sopenharmony_ci	}
10798c2ecf20Sopenharmony_ci
10808c2ecf20Sopenharmony_ci	s->control_register &= ~HDSP_LatencyMask;
10818c2ecf20Sopenharmony_ci	s->control_register |= hdsp_encode_latency(n);
10828c2ecf20Sopenharmony_ci
10838c2ecf20Sopenharmony_ci	hdsp_write(s, HDSP_controlRegister, s->control_register);
10848c2ecf20Sopenharmony_ci
10858c2ecf20Sopenharmony_ci	hdsp_compute_period_size(s);
10868c2ecf20Sopenharmony_ci
10878c2ecf20Sopenharmony_ci	spin_unlock_irq(&s->lock);
10888c2ecf20Sopenharmony_ci
10898c2ecf20Sopenharmony_ci	return 0;
10908c2ecf20Sopenharmony_ci}
10918c2ecf20Sopenharmony_ci
10928c2ecf20Sopenharmony_cistatic void hdsp_set_dds_value(struct hdsp *hdsp, int rate)
10938c2ecf20Sopenharmony_ci{
10948c2ecf20Sopenharmony_ci	u64 n;
10958c2ecf20Sopenharmony_ci
10968c2ecf20Sopenharmony_ci	if (rate >= 112000)
10978c2ecf20Sopenharmony_ci		rate /= 4;
10988c2ecf20Sopenharmony_ci	else if (rate >= 56000)
10998c2ecf20Sopenharmony_ci		rate /= 2;
11008c2ecf20Sopenharmony_ci
11018c2ecf20Sopenharmony_ci	n = DDS_NUMERATOR;
11028c2ecf20Sopenharmony_ci	n = div_u64(n, rate);
11038c2ecf20Sopenharmony_ci	/* n should be less than 2^32 for being written to FREQ register */
11048c2ecf20Sopenharmony_ci	snd_BUG_ON(n >> 32);
11058c2ecf20Sopenharmony_ci	/* HDSP_freqReg and HDSP_resetPointer are the same, so keep the DDS
11068c2ecf20Sopenharmony_ci	   value to write it after a reset */
11078c2ecf20Sopenharmony_ci	hdsp->dds_value = n;
11088c2ecf20Sopenharmony_ci	hdsp_write(hdsp, HDSP_freqReg, hdsp->dds_value);
11098c2ecf20Sopenharmony_ci}
11108c2ecf20Sopenharmony_ci
11118c2ecf20Sopenharmony_cistatic int hdsp_set_rate(struct hdsp *hdsp, int rate, int called_internally)
11128c2ecf20Sopenharmony_ci{
11138c2ecf20Sopenharmony_ci	int reject_if_open = 0;
11148c2ecf20Sopenharmony_ci	int current_rate;
11158c2ecf20Sopenharmony_ci	int rate_bits;
11168c2ecf20Sopenharmony_ci
11178c2ecf20Sopenharmony_ci	/* ASSUMPTION: hdsp->lock is either held, or
11188c2ecf20Sopenharmony_ci	   there is no need for it (e.g. during module
11198c2ecf20Sopenharmony_ci	   initialization).
11208c2ecf20Sopenharmony_ci	*/
11218c2ecf20Sopenharmony_ci
11228c2ecf20Sopenharmony_ci	if (!(hdsp->control_register & HDSP_ClockModeMaster)) {
11238c2ecf20Sopenharmony_ci		if (called_internally) {
11248c2ecf20Sopenharmony_ci			/* request from ctl or card initialization */
11258c2ecf20Sopenharmony_ci			dev_err(hdsp->card->dev,
11268c2ecf20Sopenharmony_ci				"device is not running as a clock master: cannot set sample rate.\n");
11278c2ecf20Sopenharmony_ci			return -1;
11288c2ecf20Sopenharmony_ci		} else {
11298c2ecf20Sopenharmony_ci			/* hw_param request while in AutoSync mode */
11308c2ecf20Sopenharmony_ci			int external_freq = hdsp_external_sample_rate(hdsp);
11318c2ecf20Sopenharmony_ci			int spdif_freq = hdsp_spdif_sample_rate(hdsp);
11328c2ecf20Sopenharmony_ci
11338c2ecf20Sopenharmony_ci			if ((spdif_freq == external_freq*2) && (hdsp_autosync_ref(hdsp) >= HDSP_AUTOSYNC_FROM_ADAT1))
11348c2ecf20Sopenharmony_ci				dev_info(hdsp->card->dev,
11358c2ecf20Sopenharmony_ci					 "Detected ADAT in double speed mode\n");
11368c2ecf20Sopenharmony_ci			else if (hdsp->io_type == H9632 && (spdif_freq == external_freq*4) && (hdsp_autosync_ref(hdsp) >= HDSP_AUTOSYNC_FROM_ADAT1))
11378c2ecf20Sopenharmony_ci				dev_info(hdsp->card->dev,
11388c2ecf20Sopenharmony_ci					 "Detected ADAT in quad speed mode\n");
11398c2ecf20Sopenharmony_ci			else if (rate != external_freq) {
11408c2ecf20Sopenharmony_ci				dev_info(hdsp->card->dev,
11418c2ecf20Sopenharmony_ci					 "No AutoSync source for requested rate\n");
11428c2ecf20Sopenharmony_ci				return -1;
11438c2ecf20Sopenharmony_ci			}
11448c2ecf20Sopenharmony_ci		}
11458c2ecf20Sopenharmony_ci	}
11468c2ecf20Sopenharmony_ci
11478c2ecf20Sopenharmony_ci	current_rate = hdsp->system_sample_rate;
11488c2ecf20Sopenharmony_ci
11498c2ecf20Sopenharmony_ci	/* Changing from a "single speed" to a "double speed" rate is
11508c2ecf20Sopenharmony_ci	   not allowed if any substreams are open. This is because
11518c2ecf20Sopenharmony_ci	   such a change causes a shift in the location of
11528c2ecf20Sopenharmony_ci	   the DMA buffers and a reduction in the number of available
11538c2ecf20Sopenharmony_ci	   buffers.
11548c2ecf20Sopenharmony_ci
11558c2ecf20Sopenharmony_ci	   Note that a similar but essentially insoluble problem
11568c2ecf20Sopenharmony_ci	   exists for externally-driven rate changes. All we can do
11578c2ecf20Sopenharmony_ci	   is to flag rate changes in the read/write routines.  */
11588c2ecf20Sopenharmony_ci
11598c2ecf20Sopenharmony_ci	if (rate > 96000 && hdsp->io_type != H9632)
11608c2ecf20Sopenharmony_ci		return -EINVAL;
11618c2ecf20Sopenharmony_ci
11628c2ecf20Sopenharmony_ci	switch (rate) {
11638c2ecf20Sopenharmony_ci	case 32000:
11648c2ecf20Sopenharmony_ci		if (current_rate > 48000)
11658c2ecf20Sopenharmony_ci			reject_if_open = 1;
11668c2ecf20Sopenharmony_ci		rate_bits = HDSP_Frequency32KHz;
11678c2ecf20Sopenharmony_ci		break;
11688c2ecf20Sopenharmony_ci	case 44100:
11698c2ecf20Sopenharmony_ci		if (current_rate > 48000)
11708c2ecf20Sopenharmony_ci			reject_if_open = 1;
11718c2ecf20Sopenharmony_ci		rate_bits = HDSP_Frequency44_1KHz;
11728c2ecf20Sopenharmony_ci		break;
11738c2ecf20Sopenharmony_ci	case 48000:
11748c2ecf20Sopenharmony_ci		if (current_rate > 48000)
11758c2ecf20Sopenharmony_ci			reject_if_open = 1;
11768c2ecf20Sopenharmony_ci		rate_bits = HDSP_Frequency48KHz;
11778c2ecf20Sopenharmony_ci		break;
11788c2ecf20Sopenharmony_ci	case 64000:
11798c2ecf20Sopenharmony_ci		if (current_rate <= 48000 || current_rate > 96000)
11808c2ecf20Sopenharmony_ci			reject_if_open = 1;
11818c2ecf20Sopenharmony_ci		rate_bits = HDSP_Frequency64KHz;
11828c2ecf20Sopenharmony_ci		break;
11838c2ecf20Sopenharmony_ci	case 88200:
11848c2ecf20Sopenharmony_ci		if (current_rate <= 48000 || current_rate > 96000)
11858c2ecf20Sopenharmony_ci			reject_if_open = 1;
11868c2ecf20Sopenharmony_ci		rate_bits = HDSP_Frequency88_2KHz;
11878c2ecf20Sopenharmony_ci		break;
11888c2ecf20Sopenharmony_ci	case 96000:
11898c2ecf20Sopenharmony_ci		if (current_rate <= 48000 || current_rate > 96000)
11908c2ecf20Sopenharmony_ci			reject_if_open = 1;
11918c2ecf20Sopenharmony_ci		rate_bits = HDSP_Frequency96KHz;
11928c2ecf20Sopenharmony_ci		break;
11938c2ecf20Sopenharmony_ci	case 128000:
11948c2ecf20Sopenharmony_ci		if (current_rate < 128000)
11958c2ecf20Sopenharmony_ci			reject_if_open = 1;
11968c2ecf20Sopenharmony_ci		rate_bits = HDSP_Frequency128KHz;
11978c2ecf20Sopenharmony_ci		break;
11988c2ecf20Sopenharmony_ci	case 176400:
11998c2ecf20Sopenharmony_ci		if (current_rate < 128000)
12008c2ecf20Sopenharmony_ci			reject_if_open = 1;
12018c2ecf20Sopenharmony_ci		rate_bits = HDSP_Frequency176_4KHz;
12028c2ecf20Sopenharmony_ci		break;
12038c2ecf20Sopenharmony_ci	case 192000:
12048c2ecf20Sopenharmony_ci		if (current_rate < 128000)
12058c2ecf20Sopenharmony_ci			reject_if_open = 1;
12068c2ecf20Sopenharmony_ci		rate_bits = HDSP_Frequency192KHz;
12078c2ecf20Sopenharmony_ci		break;
12088c2ecf20Sopenharmony_ci	default:
12098c2ecf20Sopenharmony_ci		return -EINVAL;
12108c2ecf20Sopenharmony_ci	}
12118c2ecf20Sopenharmony_ci
12128c2ecf20Sopenharmony_ci	if (reject_if_open && (hdsp->capture_pid >= 0 || hdsp->playback_pid >= 0)) {
12138c2ecf20Sopenharmony_ci		dev_warn(hdsp->card->dev,
12148c2ecf20Sopenharmony_ci			 "cannot change speed mode (capture PID = %d, playback PID = %d)\n",
12158c2ecf20Sopenharmony_ci			    hdsp->capture_pid,
12168c2ecf20Sopenharmony_ci			    hdsp->playback_pid);
12178c2ecf20Sopenharmony_ci		return -EBUSY;
12188c2ecf20Sopenharmony_ci	}
12198c2ecf20Sopenharmony_ci
12208c2ecf20Sopenharmony_ci	hdsp->control_register &= ~HDSP_FrequencyMask;
12218c2ecf20Sopenharmony_ci	hdsp->control_register |= rate_bits;
12228c2ecf20Sopenharmony_ci	hdsp_write(hdsp, HDSP_controlRegister, hdsp->control_register);
12238c2ecf20Sopenharmony_ci
12248c2ecf20Sopenharmony_ci	/* For HDSP9632 rev 152, need to set DDS value in FREQ register */
12258c2ecf20Sopenharmony_ci	if (hdsp->io_type == H9632 && hdsp->firmware_rev >= 152)
12268c2ecf20Sopenharmony_ci		hdsp_set_dds_value(hdsp, rate);
12278c2ecf20Sopenharmony_ci
12288c2ecf20Sopenharmony_ci	if (rate >= 128000) {
12298c2ecf20Sopenharmony_ci		hdsp->channel_map = channel_map_H9632_qs;
12308c2ecf20Sopenharmony_ci	} else if (rate > 48000) {
12318c2ecf20Sopenharmony_ci		if (hdsp->io_type == H9632)
12328c2ecf20Sopenharmony_ci			hdsp->channel_map = channel_map_H9632_ds;
12338c2ecf20Sopenharmony_ci		else
12348c2ecf20Sopenharmony_ci			hdsp->channel_map = channel_map_ds;
12358c2ecf20Sopenharmony_ci	} else {
12368c2ecf20Sopenharmony_ci		switch (hdsp->io_type) {
12378c2ecf20Sopenharmony_ci		case RPM:
12388c2ecf20Sopenharmony_ci		case Multiface:
12398c2ecf20Sopenharmony_ci			hdsp->channel_map = channel_map_mf_ss;
12408c2ecf20Sopenharmony_ci			break;
12418c2ecf20Sopenharmony_ci		case Digiface:
12428c2ecf20Sopenharmony_ci		case H9652:
12438c2ecf20Sopenharmony_ci			hdsp->channel_map = channel_map_df_ss;
12448c2ecf20Sopenharmony_ci			break;
12458c2ecf20Sopenharmony_ci		case H9632:
12468c2ecf20Sopenharmony_ci			hdsp->channel_map = channel_map_H9632_ss;
12478c2ecf20Sopenharmony_ci			break;
12488c2ecf20Sopenharmony_ci		default:
12498c2ecf20Sopenharmony_ci			/* should never happen */
12508c2ecf20Sopenharmony_ci			break;
12518c2ecf20Sopenharmony_ci		}
12528c2ecf20Sopenharmony_ci	}
12538c2ecf20Sopenharmony_ci
12548c2ecf20Sopenharmony_ci	hdsp->system_sample_rate = rate;
12558c2ecf20Sopenharmony_ci
12568c2ecf20Sopenharmony_ci	return 0;
12578c2ecf20Sopenharmony_ci}
12588c2ecf20Sopenharmony_ci
12598c2ecf20Sopenharmony_ci/*----------------------------------------------------------------------------
12608c2ecf20Sopenharmony_ci   MIDI
12618c2ecf20Sopenharmony_ci  ----------------------------------------------------------------------------*/
12628c2ecf20Sopenharmony_ci
12638c2ecf20Sopenharmony_cistatic unsigned char snd_hdsp_midi_read_byte (struct hdsp *hdsp, int id)
12648c2ecf20Sopenharmony_ci{
12658c2ecf20Sopenharmony_ci	/* the hardware already does the relevant bit-mask with 0xff */
12668c2ecf20Sopenharmony_ci	if (id)
12678c2ecf20Sopenharmony_ci		return hdsp_read(hdsp, HDSP_midiDataIn1);
12688c2ecf20Sopenharmony_ci	else
12698c2ecf20Sopenharmony_ci		return hdsp_read(hdsp, HDSP_midiDataIn0);
12708c2ecf20Sopenharmony_ci}
12718c2ecf20Sopenharmony_ci
12728c2ecf20Sopenharmony_cistatic void snd_hdsp_midi_write_byte (struct hdsp *hdsp, int id, int val)
12738c2ecf20Sopenharmony_ci{
12748c2ecf20Sopenharmony_ci	/* the hardware already does the relevant bit-mask with 0xff */
12758c2ecf20Sopenharmony_ci	if (id)
12768c2ecf20Sopenharmony_ci		hdsp_write(hdsp, HDSP_midiDataOut1, val);
12778c2ecf20Sopenharmony_ci	else
12788c2ecf20Sopenharmony_ci		hdsp_write(hdsp, HDSP_midiDataOut0, val);
12798c2ecf20Sopenharmony_ci}
12808c2ecf20Sopenharmony_ci
12818c2ecf20Sopenharmony_cistatic int snd_hdsp_midi_input_available (struct hdsp *hdsp, int id)
12828c2ecf20Sopenharmony_ci{
12838c2ecf20Sopenharmony_ci	if (id)
12848c2ecf20Sopenharmony_ci		return (hdsp_read(hdsp, HDSP_midiStatusIn1) & 0xff);
12858c2ecf20Sopenharmony_ci	else
12868c2ecf20Sopenharmony_ci		return (hdsp_read(hdsp, HDSP_midiStatusIn0) & 0xff);
12878c2ecf20Sopenharmony_ci}
12888c2ecf20Sopenharmony_ci
12898c2ecf20Sopenharmony_cistatic int snd_hdsp_midi_output_possible (struct hdsp *hdsp, int id)
12908c2ecf20Sopenharmony_ci{
12918c2ecf20Sopenharmony_ci	int fifo_bytes_used;
12928c2ecf20Sopenharmony_ci
12938c2ecf20Sopenharmony_ci	if (id)
12948c2ecf20Sopenharmony_ci		fifo_bytes_used = hdsp_read(hdsp, HDSP_midiStatusOut1) & 0xff;
12958c2ecf20Sopenharmony_ci	else
12968c2ecf20Sopenharmony_ci		fifo_bytes_used = hdsp_read(hdsp, HDSP_midiStatusOut0) & 0xff;
12978c2ecf20Sopenharmony_ci
12988c2ecf20Sopenharmony_ci	if (fifo_bytes_used < 128)
12998c2ecf20Sopenharmony_ci		return  128 - fifo_bytes_used;
13008c2ecf20Sopenharmony_ci	else
13018c2ecf20Sopenharmony_ci		return 0;
13028c2ecf20Sopenharmony_ci}
13038c2ecf20Sopenharmony_ci
13048c2ecf20Sopenharmony_cistatic void snd_hdsp_flush_midi_input (struct hdsp *hdsp, int id)
13058c2ecf20Sopenharmony_ci{
13068c2ecf20Sopenharmony_ci	while (snd_hdsp_midi_input_available (hdsp, id))
13078c2ecf20Sopenharmony_ci		snd_hdsp_midi_read_byte (hdsp, id);
13088c2ecf20Sopenharmony_ci}
13098c2ecf20Sopenharmony_ci
13108c2ecf20Sopenharmony_cistatic int snd_hdsp_midi_output_write (struct hdsp_midi *hmidi)
13118c2ecf20Sopenharmony_ci{
13128c2ecf20Sopenharmony_ci	unsigned long flags;
13138c2ecf20Sopenharmony_ci	int n_pending;
13148c2ecf20Sopenharmony_ci	int to_write;
13158c2ecf20Sopenharmony_ci	int i;
13168c2ecf20Sopenharmony_ci	unsigned char buf[128];
13178c2ecf20Sopenharmony_ci
13188c2ecf20Sopenharmony_ci	/* Output is not interrupt driven */
13198c2ecf20Sopenharmony_ci
13208c2ecf20Sopenharmony_ci	spin_lock_irqsave (&hmidi->lock, flags);
13218c2ecf20Sopenharmony_ci	if (hmidi->output) {
13228c2ecf20Sopenharmony_ci		if (!snd_rawmidi_transmit_empty (hmidi->output)) {
13238c2ecf20Sopenharmony_ci			if ((n_pending = snd_hdsp_midi_output_possible (hmidi->hdsp, hmidi->id)) > 0) {
13248c2ecf20Sopenharmony_ci				if (n_pending > (int)sizeof (buf))
13258c2ecf20Sopenharmony_ci					n_pending = sizeof (buf);
13268c2ecf20Sopenharmony_ci
13278c2ecf20Sopenharmony_ci				if ((to_write = snd_rawmidi_transmit (hmidi->output, buf, n_pending)) > 0) {
13288c2ecf20Sopenharmony_ci					for (i = 0; i < to_write; ++i)
13298c2ecf20Sopenharmony_ci						snd_hdsp_midi_write_byte (hmidi->hdsp, hmidi->id, buf[i]);
13308c2ecf20Sopenharmony_ci				}
13318c2ecf20Sopenharmony_ci			}
13328c2ecf20Sopenharmony_ci		}
13338c2ecf20Sopenharmony_ci	}
13348c2ecf20Sopenharmony_ci	spin_unlock_irqrestore (&hmidi->lock, flags);
13358c2ecf20Sopenharmony_ci	return 0;
13368c2ecf20Sopenharmony_ci}
13378c2ecf20Sopenharmony_ci
13388c2ecf20Sopenharmony_cistatic int snd_hdsp_midi_input_read (struct hdsp_midi *hmidi)
13398c2ecf20Sopenharmony_ci{
13408c2ecf20Sopenharmony_ci	unsigned char buf[128]; /* this buffer is designed to match the MIDI input FIFO size */
13418c2ecf20Sopenharmony_ci	unsigned long flags;
13428c2ecf20Sopenharmony_ci	int n_pending;
13438c2ecf20Sopenharmony_ci	int i;
13448c2ecf20Sopenharmony_ci
13458c2ecf20Sopenharmony_ci	spin_lock_irqsave (&hmidi->lock, flags);
13468c2ecf20Sopenharmony_ci	if ((n_pending = snd_hdsp_midi_input_available (hmidi->hdsp, hmidi->id)) > 0) {
13478c2ecf20Sopenharmony_ci		if (hmidi->input) {
13488c2ecf20Sopenharmony_ci			if (n_pending > (int)sizeof (buf))
13498c2ecf20Sopenharmony_ci				n_pending = sizeof (buf);
13508c2ecf20Sopenharmony_ci			for (i = 0; i < n_pending; ++i)
13518c2ecf20Sopenharmony_ci				buf[i] = snd_hdsp_midi_read_byte (hmidi->hdsp, hmidi->id);
13528c2ecf20Sopenharmony_ci			if (n_pending)
13538c2ecf20Sopenharmony_ci				snd_rawmidi_receive (hmidi->input, buf, n_pending);
13548c2ecf20Sopenharmony_ci		} else {
13558c2ecf20Sopenharmony_ci			/* flush the MIDI input FIFO */
13568c2ecf20Sopenharmony_ci			while (--n_pending)
13578c2ecf20Sopenharmony_ci				snd_hdsp_midi_read_byte (hmidi->hdsp, hmidi->id);
13588c2ecf20Sopenharmony_ci		}
13598c2ecf20Sopenharmony_ci	}
13608c2ecf20Sopenharmony_ci	hmidi->pending = 0;
13618c2ecf20Sopenharmony_ci	if (hmidi->id)
13628c2ecf20Sopenharmony_ci		hmidi->hdsp->control_register |= HDSP_Midi1InterruptEnable;
13638c2ecf20Sopenharmony_ci	else
13648c2ecf20Sopenharmony_ci		hmidi->hdsp->control_register |= HDSP_Midi0InterruptEnable;
13658c2ecf20Sopenharmony_ci	hdsp_write(hmidi->hdsp, HDSP_controlRegister, hmidi->hdsp->control_register);
13668c2ecf20Sopenharmony_ci	spin_unlock_irqrestore (&hmidi->lock, flags);
13678c2ecf20Sopenharmony_ci	return snd_hdsp_midi_output_write (hmidi);
13688c2ecf20Sopenharmony_ci}
13698c2ecf20Sopenharmony_ci
13708c2ecf20Sopenharmony_cistatic void snd_hdsp_midi_input_trigger(struct snd_rawmidi_substream *substream, int up)
13718c2ecf20Sopenharmony_ci{
13728c2ecf20Sopenharmony_ci	struct hdsp *hdsp;
13738c2ecf20Sopenharmony_ci	struct hdsp_midi *hmidi;
13748c2ecf20Sopenharmony_ci	unsigned long flags;
13758c2ecf20Sopenharmony_ci	u32 ie;
13768c2ecf20Sopenharmony_ci
13778c2ecf20Sopenharmony_ci	hmidi = (struct hdsp_midi *) substream->rmidi->private_data;
13788c2ecf20Sopenharmony_ci	hdsp = hmidi->hdsp;
13798c2ecf20Sopenharmony_ci	ie = hmidi->id ? HDSP_Midi1InterruptEnable : HDSP_Midi0InterruptEnable;
13808c2ecf20Sopenharmony_ci	spin_lock_irqsave (&hdsp->lock, flags);
13818c2ecf20Sopenharmony_ci	if (up) {
13828c2ecf20Sopenharmony_ci		if (!(hdsp->control_register & ie)) {
13838c2ecf20Sopenharmony_ci			snd_hdsp_flush_midi_input (hdsp, hmidi->id);
13848c2ecf20Sopenharmony_ci			hdsp->control_register |= ie;
13858c2ecf20Sopenharmony_ci		}
13868c2ecf20Sopenharmony_ci	} else {
13878c2ecf20Sopenharmony_ci		hdsp->control_register &= ~ie;
13888c2ecf20Sopenharmony_ci	}
13898c2ecf20Sopenharmony_ci
13908c2ecf20Sopenharmony_ci	hdsp_write(hdsp, HDSP_controlRegister, hdsp->control_register);
13918c2ecf20Sopenharmony_ci	spin_unlock_irqrestore (&hdsp->lock, flags);
13928c2ecf20Sopenharmony_ci}
13938c2ecf20Sopenharmony_ci
13948c2ecf20Sopenharmony_cistatic void snd_hdsp_midi_output_timer(struct timer_list *t)
13958c2ecf20Sopenharmony_ci{
13968c2ecf20Sopenharmony_ci	struct hdsp_midi *hmidi = from_timer(hmidi, t, timer);
13978c2ecf20Sopenharmony_ci	unsigned long flags;
13988c2ecf20Sopenharmony_ci
13998c2ecf20Sopenharmony_ci	snd_hdsp_midi_output_write(hmidi);
14008c2ecf20Sopenharmony_ci	spin_lock_irqsave (&hmidi->lock, flags);
14018c2ecf20Sopenharmony_ci
14028c2ecf20Sopenharmony_ci	/* this does not bump hmidi->istimer, because the
14038c2ecf20Sopenharmony_ci	   kernel automatically removed the timer when it
14048c2ecf20Sopenharmony_ci	   expired, and we are now adding it back, thus
14058c2ecf20Sopenharmony_ci	   leaving istimer wherever it was set before.
14068c2ecf20Sopenharmony_ci	*/
14078c2ecf20Sopenharmony_ci
14088c2ecf20Sopenharmony_ci	if (hmidi->istimer)
14098c2ecf20Sopenharmony_ci		mod_timer(&hmidi->timer, 1 + jiffies);
14108c2ecf20Sopenharmony_ci
14118c2ecf20Sopenharmony_ci	spin_unlock_irqrestore (&hmidi->lock, flags);
14128c2ecf20Sopenharmony_ci}
14138c2ecf20Sopenharmony_ci
14148c2ecf20Sopenharmony_cistatic void snd_hdsp_midi_output_trigger(struct snd_rawmidi_substream *substream, int up)
14158c2ecf20Sopenharmony_ci{
14168c2ecf20Sopenharmony_ci	struct hdsp_midi *hmidi;
14178c2ecf20Sopenharmony_ci	unsigned long flags;
14188c2ecf20Sopenharmony_ci
14198c2ecf20Sopenharmony_ci	hmidi = (struct hdsp_midi *) substream->rmidi->private_data;
14208c2ecf20Sopenharmony_ci	spin_lock_irqsave (&hmidi->lock, flags);
14218c2ecf20Sopenharmony_ci	if (up) {
14228c2ecf20Sopenharmony_ci		if (!hmidi->istimer) {
14238c2ecf20Sopenharmony_ci			timer_setup(&hmidi->timer, snd_hdsp_midi_output_timer,
14248c2ecf20Sopenharmony_ci				    0);
14258c2ecf20Sopenharmony_ci			mod_timer(&hmidi->timer, 1 + jiffies);
14268c2ecf20Sopenharmony_ci			hmidi->istimer++;
14278c2ecf20Sopenharmony_ci		}
14288c2ecf20Sopenharmony_ci	} else {
14298c2ecf20Sopenharmony_ci		if (hmidi->istimer && --hmidi->istimer <= 0)
14308c2ecf20Sopenharmony_ci			del_timer (&hmidi->timer);
14318c2ecf20Sopenharmony_ci	}
14328c2ecf20Sopenharmony_ci	spin_unlock_irqrestore (&hmidi->lock, flags);
14338c2ecf20Sopenharmony_ci	if (up)
14348c2ecf20Sopenharmony_ci		snd_hdsp_midi_output_write(hmidi);
14358c2ecf20Sopenharmony_ci}
14368c2ecf20Sopenharmony_ci
14378c2ecf20Sopenharmony_cistatic int snd_hdsp_midi_input_open(struct snd_rawmidi_substream *substream)
14388c2ecf20Sopenharmony_ci{
14398c2ecf20Sopenharmony_ci	struct hdsp_midi *hmidi;
14408c2ecf20Sopenharmony_ci
14418c2ecf20Sopenharmony_ci	hmidi = (struct hdsp_midi *) substream->rmidi->private_data;
14428c2ecf20Sopenharmony_ci	spin_lock_irq (&hmidi->lock);
14438c2ecf20Sopenharmony_ci	snd_hdsp_flush_midi_input (hmidi->hdsp, hmidi->id);
14448c2ecf20Sopenharmony_ci	hmidi->input = substream;
14458c2ecf20Sopenharmony_ci	spin_unlock_irq (&hmidi->lock);
14468c2ecf20Sopenharmony_ci
14478c2ecf20Sopenharmony_ci	return 0;
14488c2ecf20Sopenharmony_ci}
14498c2ecf20Sopenharmony_ci
14508c2ecf20Sopenharmony_cistatic int snd_hdsp_midi_output_open(struct snd_rawmidi_substream *substream)
14518c2ecf20Sopenharmony_ci{
14528c2ecf20Sopenharmony_ci	struct hdsp_midi *hmidi;
14538c2ecf20Sopenharmony_ci
14548c2ecf20Sopenharmony_ci	hmidi = (struct hdsp_midi *) substream->rmidi->private_data;
14558c2ecf20Sopenharmony_ci	spin_lock_irq (&hmidi->lock);
14568c2ecf20Sopenharmony_ci	hmidi->output = substream;
14578c2ecf20Sopenharmony_ci	spin_unlock_irq (&hmidi->lock);
14588c2ecf20Sopenharmony_ci
14598c2ecf20Sopenharmony_ci	return 0;
14608c2ecf20Sopenharmony_ci}
14618c2ecf20Sopenharmony_ci
14628c2ecf20Sopenharmony_cistatic int snd_hdsp_midi_input_close(struct snd_rawmidi_substream *substream)
14638c2ecf20Sopenharmony_ci{
14648c2ecf20Sopenharmony_ci	struct hdsp_midi *hmidi;
14658c2ecf20Sopenharmony_ci
14668c2ecf20Sopenharmony_ci	snd_hdsp_midi_input_trigger (substream, 0);
14678c2ecf20Sopenharmony_ci
14688c2ecf20Sopenharmony_ci	hmidi = (struct hdsp_midi *) substream->rmidi->private_data;
14698c2ecf20Sopenharmony_ci	spin_lock_irq (&hmidi->lock);
14708c2ecf20Sopenharmony_ci	hmidi->input = NULL;
14718c2ecf20Sopenharmony_ci	spin_unlock_irq (&hmidi->lock);
14728c2ecf20Sopenharmony_ci
14738c2ecf20Sopenharmony_ci	return 0;
14748c2ecf20Sopenharmony_ci}
14758c2ecf20Sopenharmony_ci
14768c2ecf20Sopenharmony_cistatic int snd_hdsp_midi_output_close(struct snd_rawmidi_substream *substream)
14778c2ecf20Sopenharmony_ci{
14788c2ecf20Sopenharmony_ci	struct hdsp_midi *hmidi;
14798c2ecf20Sopenharmony_ci
14808c2ecf20Sopenharmony_ci	snd_hdsp_midi_output_trigger (substream, 0);
14818c2ecf20Sopenharmony_ci
14828c2ecf20Sopenharmony_ci	hmidi = (struct hdsp_midi *) substream->rmidi->private_data;
14838c2ecf20Sopenharmony_ci	spin_lock_irq (&hmidi->lock);
14848c2ecf20Sopenharmony_ci	hmidi->output = NULL;
14858c2ecf20Sopenharmony_ci	spin_unlock_irq (&hmidi->lock);
14868c2ecf20Sopenharmony_ci
14878c2ecf20Sopenharmony_ci	return 0;
14888c2ecf20Sopenharmony_ci}
14898c2ecf20Sopenharmony_ci
14908c2ecf20Sopenharmony_cistatic const struct snd_rawmidi_ops snd_hdsp_midi_output =
14918c2ecf20Sopenharmony_ci{
14928c2ecf20Sopenharmony_ci	.open =		snd_hdsp_midi_output_open,
14938c2ecf20Sopenharmony_ci	.close =	snd_hdsp_midi_output_close,
14948c2ecf20Sopenharmony_ci	.trigger =	snd_hdsp_midi_output_trigger,
14958c2ecf20Sopenharmony_ci};
14968c2ecf20Sopenharmony_ci
14978c2ecf20Sopenharmony_cistatic const struct snd_rawmidi_ops snd_hdsp_midi_input =
14988c2ecf20Sopenharmony_ci{
14998c2ecf20Sopenharmony_ci	.open =		snd_hdsp_midi_input_open,
15008c2ecf20Sopenharmony_ci	.close =	snd_hdsp_midi_input_close,
15018c2ecf20Sopenharmony_ci	.trigger =	snd_hdsp_midi_input_trigger,
15028c2ecf20Sopenharmony_ci};
15038c2ecf20Sopenharmony_ci
15048c2ecf20Sopenharmony_cistatic int snd_hdsp_create_midi (struct snd_card *card, struct hdsp *hdsp, int id)
15058c2ecf20Sopenharmony_ci{
15068c2ecf20Sopenharmony_ci	char buf[40];
15078c2ecf20Sopenharmony_ci
15088c2ecf20Sopenharmony_ci	hdsp->midi[id].id = id;
15098c2ecf20Sopenharmony_ci	hdsp->midi[id].rmidi = NULL;
15108c2ecf20Sopenharmony_ci	hdsp->midi[id].input = NULL;
15118c2ecf20Sopenharmony_ci	hdsp->midi[id].output = NULL;
15128c2ecf20Sopenharmony_ci	hdsp->midi[id].hdsp = hdsp;
15138c2ecf20Sopenharmony_ci	hdsp->midi[id].istimer = 0;
15148c2ecf20Sopenharmony_ci	hdsp->midi[id].pending = 0;
15158c2ecf20Sopenharmony_ci	spin_lock_init (&hdsp->midi[id].lock);
15168c2ecf20Sopenharmony_ci
15178c2ecf20Sopenharmony_ci	snprintf(buf, sizeof(buf), "%s MIDI %d", card->shortname, id + 1);
15188c2ecf20Sopenharmony_ci	if (snd_rawmidi_new (card, buf, id, 1, 1, &hdsp->midi[id].rmidi) < 0)
15198c2ecf20Sopenharmony_ci		return -1;
15208c2ecf20Sopenharmony_ci
15218c2ecf20Sopenharmony_ci	sprintf(hdsp->midi[id].rmidi->name, "HDSP MIDI %d", id+1);
15228c2ecf20Sopenharmony_ci	hdsp->midi[id].rmidi->private_data = &hdsp->midi[id];
15238c2ecf20Sopenharmony_ci
15248c2ecf20Sopenharmony_ci	snd_rawmidi_set_ops (hdsp->midi[id].rmidi, SNDRV_RAWMIDI_STREAM_OUTPUT, &snd_hdsp_midi_output);
15258c2ecf20Sopenharmony_ci	snd_rawmidi_set_ops (hdsp->midi[id].rmidi, SNDRV_RAWMIDI_STREAM_INPUT, &snd_hdsp_midi_input);
15268c2ecf20Sopenharmony_ci
15278c2ecf20Sopenharmony_ci	hdsp->midi[id].rmidi->info_flags |= SNDRV_RAWMIDI_INFO_OUTPUT |
15288c2ecf20Sopenharmony_ci		SNDRV_RAWMIDI_INFO_INPUT |
15298c2ecf20Sopenharmony_ci		SNDRV_RAWMIDI_INFO_DUPLEX;
15308c2ecf20Sopenharmony_ci
15318c2ecf20Sopenharmony_ci	return 0;
15328c2ecf20Sopenharmony_ci}
15338c2ecf20Sopenharmony_ci
15348c2ecf20Sopenharmony_ci/*-----------------------------------------------------------------------------
15358c2ecf20Sopenharmony_ci  Control Interface
15368c2ecf20Sopenharmony_ci  ----------------------------------------------------------------------------*/
15378c2ecf20Sopenharmony_ci
15388c2ecf20Sopenharmony_cistatic u32 snd_hdsp_convert_from_aes(struct snd_aes_iec958 *aes)
15398c2ecf20Sopenharmony_ci{
15408c2ecf20Sopenharmony_ci	u32 val = 0;
15418c2ecf20Sopenharmony_ci	val |= (aes->status[0] & IEC958_AES0_PROFESSIONAL) ? HDSP_SPDIFProfessional : 0;
15428c2ecf20Sopenharmony_ci	val |= (aes->status[0] & IEC958_AES0_NONAUDIO) ? HDSP_SPDIFNonAudio : 0;
15438c2ecf20Sopenharmony_ci	if (val & HDSP_SPDIFProfessional)
15448c2ecf20Sopenharmony_ci		val |= (aes->status[0] & IEC958_AES0_PRO_EMPHASIS_5015) ? HDSP_SPDIFEmphasis : 0;
15458c2ecf20Sopenharmony_ci	else
15468c2ecf20Sopenharmony_ci		val |= (aes->status[0] & IEC958_AES0_CON_EMPHASIS_5015) ? HDSP_SPDIFEmphasis : 0;
15478c2ecf20Sopenharmony_ci	return val;
15488c2ecf20Sopenharmony_ci}
15498c2ecf20Sopenharmony_ci
15508c2ecf20Sopenharmony_cistatic void snd_hdsp_convert_to_aes(struct snd_aes_iec958 *aes, u32 val)
15518c2ecf20Sopenharmony_ci{
15528c2ecf20Sopenharmony_ci	aes->status[0] = ((val & HDSP_SPDIFProfessional) ? IEC958_AES0_PROFESSIONAL : 0) |
15538c2ecf20Sopenharmony_ci			 ((val & HDSP_SPDIFNonAudio) ? IEC958_AES0_NONAUDIO : 0);
15548c2ecf20Sopenharmony_ci	if (val & HDSP_SPDIFProfessional)
15558c2ecf20Sopenharmony_ci		aes->status[0] |= (val & HDSP_SPDIFEmphasis) ? IEC958_AES0_PRO_EMPHASIS_5015 : 0;
15568c2ecf20Sopenharmony_ci	else
15578c2ecf20Sopenharmony_ci		aes->status[0] |= (val & HDSP_SPDIFEmphasis) ? IEC958_AES0_CON_EMPHASIS_5015 : 0;
15588c2ecf20Sopenharmony_ci}
15598c2ecf20Sopenharmony_ci
15608c2ecf20Sopenharmony_cistatic int snd_hdsp_control_spdif_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
15618c2ecf20Sopenharmony_ci{
15628c2ecf20Sopenharmony_ci	uinfo->type = SNDRV_CTL_ELEM_TYPE_IEC958;
15638c2ecf20Sopenharmony_ci	uinfo->count = 1;
15648c2ecf20Sopenharmony_ci	return 0;
15658c2ecf20Sopenharmony_ci}
15668c2ecf20Sopenharmony_ci
15678c2ecf20Sopenharmony_cistatic int snd_hdsp_control_spdif_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
15688c2ecf20Sopenharmony_ci{
15698c2ecf20Sopenharmony_ci	struct hdsp *hdsp = snd_kcontrol_chip(kcontrol);
15708c2ecf20Sopenharmony_ci
15718c2ecf20Sopenharmony_ci	snd_hdsp_convert_to_aes(&ucontrol->value.iec958, hdsp->creg_spdif);
15728c2ecf20Sopenharmony_ci	return 0;
15738c2ecf20Sopenharmony_ci}
15748c2ecf20Sopenharmony_ci
15758c2ecf20Sopenharmony_cistatic int snd_hdsp_control_spdif_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
15768c2ecf20Sopenharmony_ci{
15778c2ecf20Sopenharmony_ci	struct hdsp *hdsp = snd_kcontrol_chip(kcontrol);
15788c2ecf20Sopenharmony_ci	int change;
15798c2ecf20Sopenharmony_ci	u32 val;
15808c2ecf20Sopenharmony_ci
15818c2ecf20Sopenharmony_ci	val = snd_hdsp_convert_from_aes(&ucontrol->value.iec958);
15828c2ecf20Sopenharmony_ci	spin_lock_irq(&hdsp->lock);
15838c2ecf20Sopenharmony_ci	change = val != hdsp->creg_spdif;
15848c2ecf20Sopenharmony_ci	hdsp->creg_spdif = val;
15858c2ecf20Sopenharmony_ci	spin_unlock_irq(&hdsp->lock);
15868c2ecf20Sopenharmony_ci	return change;
15878c2ecf20Sopenharmony_ci}
15888c2ecf20Sopenharmony_ci
15898c2ecf20Sopenharmony_cistatic int snd_hdsp_control_spdif_stream_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
15908c2ecf20Sopenharmony_ci{
15918c2ecf20Sopenharmony_ci	uinfo->type = SNDRV_CTL_ELEM_TYPE_IEC958;
15928c2ecf20Sopenharmony_ci	uinfo->count = 1;
15938c2ecf20Sopenharmony_ci	return 0;
15948c2ecf20Sopenharmony_ci}
15958c2ecf20Sopenharmony_ci
15968c2ecf20Sopenharmony_cistatic int snd_hdsp_control_spdif_stream_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
15978c2ecf20Sopenharmony_ci{
15988c2ecf20Sopenharmony_ci	struct hdsp *hdsp = snd_kcontrol_chip(kcontrol);
15998c2ecf20Sopenharmony_ci
16008c2ecf20Sopenharmony_ci	snd_hdsp_convert_to_aes(&ucontrol->value.iec958, hdsp->creg_spdif_stream);
16018c2ecf20Sopenharmony_ci	return 0;
16028c2ecf20Sopenharmony_ci}
16038c2ecf20Sopenharmony_ci
16048c2ecf20Sopenharmony_cistatic int snd_hdsp_control_spdif_stream_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
16058c2ecf20Sopenharmony_ci{
16068c2ecf20Sopenharmony_ci	struct hdsp *hdsp = snd_kcontrol_chip(kcontrol);
16078c2ecf20Sopenharmony_ci	int change;
16088c2ecf20Sopenharmony_ci	u32 val;
16098c2ecf20Sopenharmony_ci
16108c2ecf20Sopenharmony_ci	val = snd_hdsp_convert_from_aes(&ucontrol->value.iec958);
16118c2ecf20Sopenharmony_ci	spin_lock_irq(&hdsp->lock);
16128c2ecf20Sopenharmony_ci	change = val != hdsp->creg_spdif_stream;
16138c2ecf20Sopenharmony_ci	hdsp->creg_spdif_stream = val;
16148c2ecf20Sopenharmony_ci	hdsp->control_register &= ~(HDSP_SPDIFProfessional | HDSP_SPDIFNonAudio | HDSP_SPDIFEmphasis);
16158c2ecf20Sopenharmony_ci	hdsp_write(hdsp, HDSP_controlRegister, hdsp->control_register |= val);
16168c2ecf20Sopenharmony_ci	spin_unlock_irq(&hdsp->lock);
16178c2ecf20Sopenharmony_ci	return change;
16188c2ecf20Sopenharmony_ci}
16198c2ecf20Sopenharmony_ci
16208c2ecf20Sopenharmony_cistatic int snd_hdsp_control_spdif_mask_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
16218c2ecf20Sopenharmony_ci{
16228c2ecf20Sopenharmony_ci	uinfo->type = SNDRV_CTL_ELEM_TYPE_IEC958;
16238c2ecf20Sopenharmony_ci	uinfo->count = 1;
16248c2ecf20Sopenharmony_ci	return 0;
16258c2ecf20Sopenharmony_ci}
16268c2ecf20Sopenharmony_ci
16278c2ecf20Sopenharmony_cistatic int snd_hdsp_control_spdif_mask_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
16288c2ecf20Sopenharmony_ci{
16298c2ecf20Sopenharmony_ci	ucontrol->value.iec958.status[0] = kcontrol->private_value;
16308c2ecf20Sopenharmony_ci	return 0;
16318c2ecf20Sopenharmony_ci}
16328c2ecf20Sopenharmony_ci
16338c2ecf20Sopenharmony_ci#define HDSP_SPDIF_IN(xname, xindex) \
16348c2ecf20Sopenharmony_ci{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
16358c2ecf20Sopenharmony_ci  .name = xname, \
16368c2ecf20Sopenharmony_ci  .index = xindex, \
16378c2ecf20Sopenharmony_ci  .info = snd_hdsp_info_spdif_in, \
16388c2ecf20Sopenharmony_ci  .get = snd_hdsp_get_spdif_in, \
16398c2ecf20Sopenharmony_ci  .put = snd_hdsp_put_spdif_in }
16408c2ecf20Sopenharmony_ci
16418c2ecf20Sopenharmony_cistatic unsigned int hdsp_spdif_in(struct hdsp *hdsp)
16428c2ecf20Sopenharmony_ci{
16438c2ecf20Sopenharmony_ci	return hdsp_decode_spdif_in(hdsp->control_register & HDSP_SPDIFInputMask);
16448c2ecf20Sopenharmony_ci}
16458c2ecf20Sopenharmony_ci
16468c2ecf20Sopenharmony_cistatic int hdsp_set_spdif_input(struct hdsp *hdsp, int in)
16478c2ecf20Sopenharmony_ci{
16488c2ecf20Sopenharmony_ci	hdsp->control_register &= ~HDSP_SPDIFInputMask;
16498c2ecf20Sopenharmony_ci	hdsp->control_register |= hdsp_encode_spdif_in(in);
16508c2ecf20Sopenharmony_ci	hdsp_write(hdsp, HDSP_controlRegister, hdsp->control_register);
16518c2ecf20Sopenharmony_ci	return 0;
16528c2ecf20Sopenharmony_ci}
16538c2ecf20Sopenharmony_ci
16548c2ecf20Sopenharmony_cistatic int snd_hdsp_info_spdif_in(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
16558c2ecf20Sopenharmony_ci{
16568c2ecf20Sopenharmony_ci	static const char * const texts[4] = {
16578c2ecf20Sopenharmony_ci		"Optical", "Coaxial", "Internal", "AES"
16588c2ecf20Sopenharmony_ci	};
16598c2ecf20Sopenharmony_ci	struct hdsp *hdsp = snd_kcontrol_chip(kcontrol);
16608c2ecf20Sopenharmony_ci
16618c2ecf20Sopenharmony_ci	return snd_ctl_enum_info(uinfo, 1, (hdsp->io_type == H9632) ? 4 : 3,
16628c2ecf20Sopenharmony_ci				 texts);
16638c2ecf20Sopenharmony_ci}
16648c2ecf20Sopenharmony_ci
16658c2ecf20Sopenharmony_cistatic int snd_hdsp_get_spdif_in(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
16668c2ecf20Sopenharmony_ci{
16678c2ecf20Sopenharmony_ci	struct hdsp *hdsp = snd_kcontrol_chip(kcontrol);
16688c2ecf20Sopenharmony_ci
16698c2ecf20Sopenharmony_ci	ucontrol->value.enumerated.item[0] = hdsp_spdif_in(hdsp);
16708c2ecf20Sopenharmony_ci	return 0;
16718c2ecf20Sopenharmony_ci}
16728c2ecf20Sopenharmony_ci
16738c2ecf20Sopenharmony_cistatic int snd_hdsp_put_spdif_in(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
16748c2ecf20Sopenharmony_ci{
16758c2ecf20Sopenharmony_ci	struct hdsp *hdsp = snd_kcontrol_chip(kcontrol);
16768c2ecf20Sopenharmony_ci	int change;
16778c2ecf20Sopenharmony_ci	unsigned int val;
16788c2ecf20Sopenharmony_ci
16798c2ecf20Sopenharmony_ci	if (!snd_hdsp_use_is_exclusive(hdsp))
16808c2ecf20Sopenharmony_ci		return -EBUSY;
16818c2ecf20Sopenharmony_ci	val = ucontrol->value.enumerated.item[0] % ((hdsp->io_type == H9632) ? 4 : 3);
16828c2ecf20Sopenharmony_ci	spin_lock_irq(&hdsp->lock);
16838c2ecf20Sopenharmony_ci	change = val != hdsp_spdif_in(hdsp);
16848c2ecf20Sopenharmony_ci	if (change)
16858c2ecf20Sopenharmony_ci		hdsp_set_spdif_input(hdsp, val);
16868c2ecf20Sopenharmony_ci	spin_unlock_irq(&hdsp->lock);
16878c2ecf20Sopenharmony_ci	return change;
16888c2ecf20Sopenharmony_ci}
16898c2ecf20Sopenharmony_ci
16908c2ecf20Sopenharmony_ci#define HDSP_TOGGLE_SETTING(xname, xindex) \
16918c2ecf20Sopenharmony_ci{   .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
16928c2ecf20Sopenharmony_ci	.name = xname, \
16938c2ecf20Sopenharmony_ci	.private_value = xindex, \
16948c2ecf20Sopenharmony_ci	.info = snd_hdsp_info_toggle_setting, \
16958c2ecf20Sopenharmony_ci	.get = snd_hdsp_get_toggle_setting, \
16968c2ecf20Sopenharmony_ci	.put = snd_hdsp_put_toggle_setting \
16978c2ecf20Sopenharmony_ci}
16988c2ecf20Sopenharmony_ci
16998c2ecf20Sopenharmony_cistatic int hdsp_toggle_setting(struct hdsp *hdsp, u32 regmask)
17008c2ecf20Sopenharmony_ci{
17018c2ecf20Sopenharmony_ci	return (hdsp->control_register & regmask) ? 1 : 0;
17028c2ecf20Sopenharmony_ci}
17038c2ecf20Sopenharmony_ci
17048c2ecf20Sopenharmony_cistatic int hdsp_set_toggle_setting(struct hdsp *hdsp, u32 regmask, int out)
17058c2ecf20Sopenharmony_ci{
17068c2ecf20Sopenharmony_ci	if (out)
17078c2ecf20Sopenharmony_ci		hdsp->control_register |= regmask;
17088c2ecf20Sopenharmony_ci	else
17098c2ecf20Sopenharmony_ci		hdsp->control_register &= ~regmask;
17108c2ecf20Sopenharmony_ci	hdsp_write(hdsp, HDSP_controlRegister, hdsp->control_register);
17118c2ecf20Sopenharmony_ci
17128c2ecf20Sopenharmony_ci	return 0;
17138c2ecf20Sopenharmony_ci}
17148c2ecf20Sopenharmony_ci
17158c2ecf20Sopenharmony_ci#define snd_hdsp_info_toggle_setting		   snd_ctl_boolean_mono_info
17168c2ecf20Sopenharmony_ci
17178c2ecf20Sopenharmony_cistatic int snd_hdsp_get_toggle_setting(struct snd_kcontrol *kcontrol,
17188c2ecf20Sopenharmony_ci		struct snd_ctl_elem_value *ucontrol)
17198c2ecf20Sopenharmony_ci{
17208c2ecf20Sopenharmony_ci	struct hdsp *hdsp = snd_kcontrol_chip(kcontrol);
17218c2ecf20Sopenharmony_ci	u32 regmask = kcontrol->private_value;
17228c2ecf20Sopenharmony_ci
17238c2ecf20Sopenharmony_ci	spin_lock_irq(&hdsp->lock);
17248c2ecf20Sopenharmony_ci	ucontrol->value.integer.value[0] = hdsp_toggle_setting(hdsp, regmask);
17258c2ecf20Sopenharmony_ci	spin_unlock_irq(&hdsp->lock);
17268c2ecf20Sopenharmony_ci	return 0;
17278c2ecf20Sopenharmony_ci}
17288c2ecf20Sopenharmony_ci
17298c2ecf20Sopenharmony_cistatic int snd_hdsp_put_toggle_setting(struct snd_kcontrol *kcontrol,
17308c2ecf20Sopenharmony_ci		struct snd_ctl_elem_value *ucontrol)
17318c2ecf20Sopenharmony_ci{
17328c2ecf20Sopenharmony_ci	struct hdsp *hdsp = snd_kcontrol_chip(kcontrol);
17338c2ecf20Sopenharmony_ci	u32 regmask = kcontrol->private_value;
17348c2ecf20Sopenharmony_ci	int change;
17358c2ecf20Sopenharmony_ci	unsigned int val;
17368c2ecf20Sopenharmony_ci
17378c2ecf20Sopenharmony_ci	if (!snd_hdsp_use_is_exclusive(hdsp))
17388c2ecf20Sopenharmony_ci		return -EBUSY;
17398c2ecf20Sopenharmony_ci	val = ucontrol->value.integer.value[0] & 1;
17408c2ecf20Sopenharmony_ci	spin_lock_irq(&hdsp->lock);
17418c2ecf20Sopenharmony_ci	change = (int) val != hdsp_toggle_setting(hdsp, regmask);
17428c2ecf20Sopenharmony_ci	if (change)
17438c2ecf20Sopenharmony_ci		hdsp_set_toggle_setting(hdsp, regmask, val);
17448c2ecf20Sopenharmony_ci	spin_unlock_irq(&hdsp->lock);
17458c2ecf20Sopenharmony_ci	return change;
17468c2ecf20Sopenharmony_ci}
17478c2ecf20Sopenharmony_ci
17488c2ecf20Sopenharmony_ci#define HDSP_SPDIF_SAMPLE_RATE(xname, xindex) \
17498c2ecf20Sopenharmony_ci{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
17508c2ecf20Sopenharmony_ci  .name = xname, \
17518c2ecf20Sopenharmony_ci  .index = xindex, \
17528c2ecf20Sopenharmony_ci  .access = SNDRV_CTL_ELEM_ACCESS_READ, \
17538c2ecf20Sopenharmony_ci  .info = snd_hdsp_info_spdif_sample_rate, \
17548c2ecf20Sopenharmony_ci  .get = snd_hdsp_get_spdif_sample_rate \
17558c2ecf20Sopenharmony_ci}
17568c2ecf20Sopenharmony_ci
17578c2ecf20Sopenharmony_cistatic int snd_hdsp_info_spdif_sample_rate(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
17588c2ecf20Sopenharmony_ci{
17598c2ecf20Sopenharmony_ci	static const char * const texts[] = {
17608c2ecf20Sopenharmony_ci		"32000", "44100", "48000", "64000", "88200", "96000",
17618c2ecf20Sopenharmony_ci		"None", "128000", "176400", "192000"
17628c2ecf20Sopenharmony_ci	};
17638c2ecf20Sopenharmony_ci	struct hdsp *hdsp = snd_kcontrol_chip(kcontrol);
17648c2ecf20Sopenharmony_ci
17658c2ecf20Sopenharmony_ci	return snd_ctl_enum_info(uinfo, 1, (hdsp->io_type == H9632) ? 10 : 7,
17668c2ecf20Sopenharmony_ci				 texts);
17678c2ecf20Sopenharmony_ci}
17688c2ecf20Sopenharmony_ci
17698c2ecf20Sopenharmony_cistatic int snd_hdsp_get_spdif_sample_rate(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
17708c2ecf20Sopenharmony_ci{
17718c2ecf20Sopenharmony_ci	struct hdsp *hdsp = snd_kcontrol_chip(kcontrol);
17728c2ecf20Sopenharmony_ci
17738c2ecf20Sopenharmony_ci	switch (hdsp_spdif_sample_rate(hdsp)) {
17748c2ecf20Sopenharmony_ci	case 32000:
17758c2ecf20Sopenharmony_ci		ucontrol->value.enumerated.item[0] = 0;
17768c2ecf20Sopenharmony_ci		break;
17778c2ecf20Sopenharmony_ci	case 44100:
17788c2ecf20Sopenharmony_ci		ucontrol->value.enumerated.item[0] = 1;
17798c2ecf20Sopenharmony_ci		break;
17808c2ecf20Sopenharmony_ci	case 48000:
17818c2ecf20Sopenharmony_ci		ucontrol->value.enumerated.item[0] = 2;
17828c2ecf20Sopenharmony_ci		break;
17838c2ecf20Sopenharmony_ci	case 64000:
17848c2ecf20Sopenharmony_ci		ucontrol->value.enumerated.item[0] = 3;
17858c2ecf20Sopenharmony_ci		break;
17868c2ecf20Sopenharmony_ci	case 88200:
17878c2ecf20Sopenharmony_ci		ucontrol->value.enumerated.item[0] = 4;
17888c2ecf20Sopenharmony_ci		break;
17898c2ecf20Sopenharmony_ci	case 96000:
17908c2ecf20Sopenharmony_ci		ucontrol->value.enumerated.item[0] = 5;
17918c2ecf20Sopenharmony_ci		break;
17928c2ecf20Sopenharmony_ci	case 128000:
17938c2ecf20Sopenharmony_ci		ucontrol->value.enumerated.item[0] = 7;
17948c2ecf20Sopenharmony_ci		break;
17958c2ecf20Sopenharmony_ci	case 176400:
17968c2ecf20Sopenharmony_ci		ucontrol->value.enumerated.item[0] = 8;
17978c2ecf20Sopenharmony_ci		break;
17988c2ecf20Sopenharmony_ci	case 192000:
17998c2ecf20Sopenharmony_ci		ucontrol->value.enumerated.item[0] = 9;
18008c2ecf20Sopenharmony_ci		break;
18018c2ecf20Sopenharmony_ci	default:
18028c2ecf20Sopenharmony_ci		ucontrol->value.enumerated.item[0] = 6;
18038c2ecf20Sopenharmony_ci	}
18048c2ecf20Sopenharmony_ci	return 0;
18058c2ecf20Sopenharmony_ci}
18068c2ecf20Sopenharmony_ci
18078c2ecf20Sopenharmony_ci#define HDSP_SYSTEM_SAMPLE_RATE(xname, xindex) \
18088c2ecf20Sopenharmony_ci{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
18098c2ecf20Sopenharmony_ci  .name = xname, \
18108c2ecf20Sopenharmony_ci  .index = xindex, \
18118c2ecf20Sopenharmony_ci  .access = SNDRV_CTL_ELEM_ACCESS_READ, \
18128c2ecf20Sopenharmony_ci  .info = snd_hdsp_info_system_sample_rate, \
18138c2ecf20Sopenharmony_ci  .get = snd_hdsp_get_system_sample_rate \
18148c2ecf20Sopenharmony_ci}
18158c2ecf20Sopenharmony_ci
18168c2ecf20Sopenharmony_cistatic int snd_hdsp_info_system_sample_rate(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
18178c2ecf20Sopenharmony_ci{
18188c2ecf20Sopenharmony_ci	uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
18198c2ecf20Sopenharmony_ci	uinfo->count = 1;
18208c2ecf20Sopenharmony_ci	return 0;
18218c2ecf20Sopenharmony_ci}
18228c2ecf20Sopenharmony_ci
18238c2ecf20Sopenharmony_cistatic int snd_hdsp_get_system_sample_rate(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
18248c2ecf20Sopenharmony_ci{
18258c2ecf20Sopenharmony_ci	struct hdsp *hdsp = snd_kcontrol_chip(kcontrol);
18268c2ecf20Sopenharmony_ci
18278c2ecf20Sopenharmony_ci	ucontrol->value.enumerated.item[0] = hdsp->system_sample_rate;
18288c2ecf20Sopenharmony_ci	return 0;
18298c2ecf20Sopenharmony_ci}
18308c2ecf20Sopenharmony_ci
18318c2ecf20Sopenharmony_ci#define HDSP_AUTOSYNC_SAMPLE_RATE(xname, xindex) \
18328c2ecf20Sopenharmony_ci{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
18338c2ecf20Sopenharmony_ci  .name = xname, \
18348c2ecf20Sopenharmony_ci  .index = xindex, \
18358c2ecf20Sopenharmony_ci  .access = SNDRV_CTL_ELEM_ACCESS_READ, \
18368c2ecf20Sopenharmony_ci  .info = snd_hdsp_info_autosync_sample_rate, \
18378c2ecf20Sopenharmony_ci  .get = snd_hdsp_get_autosync_sample_rate \
18388c2ecf20Sopenharmony_ci}
18398c2ecf20Sopenharmony_ci
18408c2ecf20Sopenharmony_cistatic int snd_hdsp_info_autosync_sample_rate(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
18418c2ecf20Sopenharmony_ci{
18428c2ecf20Sopenharmony_ci	struct hdsp *hdsp = snd_kcontrol_chip(kcontrol);
18438c2ecf20Sopenharmony_ci	static const char * const texts[] = {
18448c2ecf20Sopenharmony_ci		"32000", "44100", "48000", "64000", "88200", "96000",
18458c2ecf20Sopenharmony_ci		"None", "128000", "176400", "192000"
18468c2ecf20Sopenharmony_ci	};
18478c2ecf20Sopenharmony_ci
18488c2ecf20Sopenharmony_ci	return snd_ctl_enum_info(uinfo, 1, (hdsp->io_type == H9632) ? 10 : 7,
18498c2ecf20Sopenharmony_ci				 texts);
18508c2ecf20Sopenharmony_ci}
18518c2ecf20Sopenharmony_ci
18528c2ecf20Sopenharmony_cistatic int snd_hdsp_get_autosync_sample_rate(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
18538c2ecf20Sopenharmony_ci{
18548c2ecf20Sopenharmony_ci	struct hdsp *hdsp = snd_kcontrol_chip(kcontrol);
18558c2ecf20Sopenharmony_ci
18568c2ecf20Sopenharmony_ci	switch (hdsp_external_sample_rate(hdsp)) {
18578c2ecf20Sopenharmony_ci	case 32000:
18588c2ecf20Sopenharmony_ci		ucontrol->value.enumerated.item[0] = 0;
18598c2ecf20Sopenharmony_ci		break;
18608c2ecf20Sopenharmony_ci	case 44100:
18618c2ecf20Sopenharmony_ci		ucontrol->value.enumerated.item[0] = 1;
18628c2ecf20Sopenharmony_ci		break;
18638c2ecf20Sopenharmony_ci	case 48000:
18648c2ecf20Sopenharmony_ci		ucontrol->value.enumerated.item[0] = 2;
18658c2ecf20Sopenharmony_ci		break;
18668c2ecf20Sopenharmony_ci	case 64000:
18678c2ecf20Sopenharmony_ci		ucontrol->value.enumerated.item[0] = 3;
18688c2ecf20Sopenharmony_ci		break;
18698c2ecf20Sopenharmony_ci	case 88200:
18708c2ecf20Sopenharmony_ci		ucontrol->value.enumerated.item[0] = 4;
18718c2ecf20Sopenharmony_ci		break;
18728c2ecf20Sopenharmony_ci	case 96000:
18738c2ecf20Sopenharmony_ci		ucontrol->value.enumerated.item[0] = 5;
18748c2ecf20Sopenharmony_ci		break;
18758c2ecf20Sopenharmony_ci	case 128000:
18768c2ecf20Sopenharmony_ci		ucontrol->value.enumerated.item[0] = 7;
18778c2ecf20Sopenharmony_ci		break;
18788c2ecf20Sopenharmony_ci	case 176400:
18798c2ecf20Sopenharmony_ci		ucontrol->value.enumerated.item[0] = 8;
18808c2ecf20Sopenharmony_ci		break;
18818c2ecf20Sopenharmony_ci	case 192000:
18828c2ecf20Sopenharmony_ci		ucontrol->value.enumerated.item[0] = 9;
18838c2ecf20Sopenharmony_ci		break;
18848c2ecf20Sopenharmony_ci	default:
18858c2ecf20Sopenharmony_ci		ucontrol->value.enumerated.item[0] = 6;
18868c2ecf20Sopenharmony_ci	}
18878c2ecf20Sopenharmony_ci	return 0;
18888c2ecf20Sopenharmony_ci}
18898c2ecf20Sopenharmony_ci
18908c2ecf20Sopenharmony_ci#define HDSP_SYSTEM_CLOCK_MODE(xname, xindex) \
18918c2ecf20Sopenharmony_ci{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
18928c2ecf20Sopenharmony_ci  .name = xname, \
18938c2ecf20Sopenharmony_ci  .index = xindex, \
18948c2ecf20Sopenharmony_ci  .access = SNDRV_CTL_ELEM_ACCESS_READ, \
18958c2ecf20Sopenharmony_ci  .info = snd_hdsp_info_system_clock_mode, \
18968c2ecf20Sopenharmony_ci  .get = snd_hdsp_get_system_clock_mode \
18978c2ecf20Sopenharmony_ci}
18988c2ecf20Sopenharmony_ci
18998c2ecf20Sopenharmony_cistatic int hdsp_system_clock_mode(struct hdsp *hdsp)
19008c2ecf20Sopenharmony_ci{
19018c2ecf20Sopenharmony_ci	if (hdsp->control_register & HDSP_ClockModeMaster)
19028c2ecf20Sopenharmony_ci		return 0;
19038c2ecf20Sopenharmony_ci	else if (hdsp_external_sample_rate(hdsp) != hdsp->system_sample_rate)
19048c2ecf20Sopenharmony_ci			return 0;
19058c2ecf20Sopenharmony_ci	return 1;
19068c2ecf20Sopenharmony_ci}
19078c2ecf20Sopenharmony_ci
19088c2ecf20Sopenharmony_cistatic int snd_hdsp_info_system_clock_mode(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
19098c2ecf20Sopenharmony_ci{
19108c2ecf20Sopenharmony_ci	static const char * const texts[] = {"Master", "Slave" };
19118c2ecf20Sopenharmony_ci
19128c2ecf20Sopenharmony_ci	return snd_ctl_enum_info(uinfo, 1, 2, texts);
19138c2ecf20Sopenharmony_ci}
19148c2ecf20Sopenharmony_ci
19158c2ecf20Sopenharmony_cistatic int snd_hdsp_get_system_clock_mode(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
19168c2ecf20Sopenharmony_ci{
19178c2ecf20Sopenharmony_ci	struct hdsp *hdsp = snd_kcontrol_chip(kcontrol);
19188c2ecf20Sopenharmony_ci
19198c2ecf20Sopenharmony_ci	ucontrol->value.enumerated.item[0] = hdsp_system_clock_mode(hdsp);
19208c2ecf20Sopenharmony_ci	return 0;
19218c2ecf20Sopenharmony_ci}
19228c2ecf20Sopenharmony_ci
19238c2ecf20Sopenharmony_ci#define HDSP_CLOCK_SOURCE(xname, xindex) \
19248c2ecf20Sopenharmony_ci{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
19258c2ecf20Sopenharmony_ci  .name = xname, \
19268c2ecf20Sopenharmony_ci  .index = xindex, \
19278c2ecf20Sopenharmony_ci  .info = snd_hdsp_info_clock_source, \
19288c2ecf20Sopenharmony_ci  .get = snd_hdsp_get_clock_source, \
19298c2ecf20Sopenharmony_ci  .put = snd_hdsp_put_clock_source \
19308c2ecf20Sopenharmony_ci}
19318c2ecf20Sopenharmony_ci
19328c2ecf20Sopenharmony_cistatic int hdsp_clock_source(struct hdsp *hdsp)
19338c2ecf20Sopenharmony_ci{
19348c2ecf20Sopenharmony_ci	if (hdsp->control_register & HDSP_ClockModeMaster) {
19358c2ecf20Sopenharmony_ci		switch (hdsp->system_sample_rate) {
19368c2ecf20Sopenharmony_ci		case 32000:
19378c2ecf20Sopenharmony_ci			return 1;
19388c2ecf20Sopenharmony_ci		case 44100:
19398c2ecf20Sopenharmony_ci			return 2;
19408c2ecf20Sopenharmony_ci		case 48000:
19418c2ecf20Sopenharmony_ci			return 3;
19428c2ecf20Sopenharmony_ci		case 64000:
19438c2ecf20Sopenharmony_ci			return 4;
19448c2ecf20Sopenharmony_ci		case 88200:
19458c2ecf20Sopenharmony_ci			return 5;
19468c2ecf20Sopenharmony_ci		case 96000:
19478c2ecf20Sopenharmony_ci			return 6;
19488c2ecf20Sopenharmony_ci		case 128000:
19498c2ecf20Sopenharmony_ci			return 7;
19508c2ecf20Sopenharmony_ci		case 176400:
19518c2ecf20Sopenharmony_ci			return 8;
19528c2ecf20Sopenharmony_ci		case 192000:
19538c2ecf20Sopenharmony_ci			return 9;
19548c2ecf20Sopenharmony_ci		default:
19558c2ecf20Sopenharmony_ci			return 3;
19568c2ecf20Sopenharmony_ci		}
19578c2ecf20Sopenharmony_ci	} else {
19588c2ecf20Sopenharmony_ci		return 0;
19598c2ecf20Sopenharmony_ci	}
19608c2ecf20Sopenharmony_ci}
19618c2ecf20Sopenharmony_ci
19628c2ecf20Sopenharmony_cistatic int hdsp_set_clock_source(struct hdsp *hdsp, int mode)
19638c2ecf20Sopenharmony_ci{
19648c2ecf20Sopenharmony_ci	int rate;
19658c2ecf20Sopenharmony_ci	switch (mode) {
19668c2ecf20Sopenharmony_ci	case HDSP_CLOCK_SOURCE_AUTOSYNC:
19678c2ecf20Sopenharmony_ci		if (hdsp_external_sample_rate(hdsp) != 0) {
19688c2ecf20Sopenharmony_ci		    if (!hdsp_set_rate(hdsp, hdsp_external_sample_rate(hdsp), 1)) {
19698c2ecf20Sopenharmony_ci			hdsp->control_register &= ~HDSP_ClockModeMaster;
19708c2ecf20Sopenharmony_ci			hdsp_write(hdsp, HDSP_controlRegister, hdsp->control_register);
19718c2ecf20Sopenharmony_ci			return 0;
19728c2ecf20Sopenharmony_ci		    }
19738c2ecf20Sopenharmony_ci		}
19748c2ecf20Sopenharmony_ci		return -1;
19758c2ecf20Sopenharmony_ci	case HDSP_CLOCK_SOURCE_INTERNAL_32KHZ:
19768c2ecf20Sopenharmony_ci		rate = 32000;
19778c2ecf20Sopenharmony_ci		break;
19788c2ecf20Sopenharmony_ci	case HDSP_CLOCK_SOURCE_INTERNAL_44_1KHZ:
19798c2ecf20Sopenharmony_ci		rate = 44100;
19808c2ecf20Sopenharmony_ci		break;
19818c2ecf20Sopenharmony_ci	case HDSP_CLOCK_SOURCE_INTERNAL_48KHZ:
19828c2ecf20Sopenharmony_ci		rate = 48000;
19838c2ecf20Sopenharmony_ci		break;
19848c2ecf20Sopenharmony_ci	case HDSP_CLOCK_SOURCE_INTERNAL_64KHZ:
19858c2ecf20Sopenharmony_ci		rate = 64000;
19868c2ecf20Sopenharmony_ci		break;
19878c2ecf20Sopenharmony_ci	case HDSP_CLOCK_SOURCE_INTERNAL_88_2KHZ:
19888c2ecf20Sopenharmony_ci		rate = 88200;
19898c2ecf20Sopenharmony_ci		break;
19908c2ecf20Sopenharmony_ci	case HDSP_CLOCK_SOURCE_INTERNAL_96KHZ:
19918c2ecf20Sopenharmony_ci		rate = 96000;
19928c2ecf20Sopenharmony_ci		break;
19938c2ecf20Sopenharmony_ci	case HDSP_CLOCK_SOURCE_INTERNAL_128KHZ:
19948c2ecf20Sopenharmony_ci		rate = 128000;
19958c2ecf20Sopenharmony_ci		break;
19968c2ecf20Sopenharmony_ci	case HDSP_CLOCK_SOURCE_INTERNAL_176_4KHZ:
19978c2ecf20Sopenharmony_ci		rate = 176400;
19988c2ecf20Sopenharmony_ci		break;
19998c2ecf20Sopenharmony_ci	case HDSP_CLOCK_SOURCE_INTERNAL_192KHZ:
20008c2ecf20Sopenharmony_ci		rate = 192000;
20018c2ecf20Sopenharmony_ci		break;
20028c2ecf20Sopenharmony_ci	default:
20038c2ecf20Sopenharmony_ci		rate = 48000;
20048c2ecf20Sopenharmony_ci	}
20058c2ecf20Sopenharmony_ci	hdsp->control_register |= HDSP_ClockModeMaster;
20068c2ecf20Sopenharmony_ci	hdsp_write(hdsp, HDSP_controlRegister, hdsp->control_register);
20078c2ecf20Sopenharmony_ci	hdsp_set_rate(hdsp, rate, 1);
20088c2ecf20Sopenharmony_ci	return 0;
20098c2ecf20Sopenharmony_ci}
20108c2ecf20Sopenharmony_ci
20118c2ecf20Sopenharmony_cistatic int snd_hdsp_info_clock_source(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
20128c2ecf20Sopenharmony_ci{
20138c2ecf20Sopenharmony_ci	static const char * const texts[] = {
20148c2ecf20Sopenharmony_ci		"AutoSync", "Internal 32.0 kHz", "Internal 44.1 kHz",
20158c2ecf20Sopenharmony_ci		"Internal 48.0 kHz", "Internal 64.0 kHz", "Internal 88.2 kHz",
20168c2ecf20Sopenharmony_ci		"Internal 96.0 kHz", "Internal 128 kHz", "Internal 176.4 kHz",
20178c2ecf20Sopenharmony_ci		"Internal 192.0 KHz"
20188c2ecf20Sopenharmony_ci	};
20198c2ecf20Sopenharmony_ci	struct hdsp *hdsp = snd_kcontrol_chip(kcontrol);
20208c2ecf20Sopenharmony_ci
20218c2ecf20Sopenharmony_ci	return snd_ctl_enum_info(uinfo, 1, (hdsp->io_type == H9632) ? 10 : 7,
20228c2ecf20Sopenharmony_ci				 texts);
20238c2ecf20Sopenharmony_ci}
20248c2ecf20Sopenharmony_ci
20258c2ecf20Sopenharmony_cistatic int snd_hdsp_get_clock_source(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
20268c2ecf20Sopenharmony_ci{
20278c2ecf20Sopenharmony_ci	struct hdsp *hdsp = snd_kcontrol_chip(kcontrol);
20288c2ecf20Sopenharmony_ci
20298c2ecf20Sopenharmony_ci	ucontrol->value.enumerated.item[0] = hdsp_clock_source(hdsp);
20308c2ecf20Sopenharmony_ci	return 0;
20318c2ecf20Sopenharmony_ci}
20328c2ecf20Sopenharmony_ci
20338c2ecf20Sopenharmony_cistatic int snd_hdsp_put_clock_source(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
20348c2ecf20Sopenharmony_ci{
20358c2ecf20Sopenharmony_ci	struct hdsp *hdsp = snd_kcontrol_chip(kcontrol);
20368c2ecf20Sopenharmony_ci	int change;
20378c2ecf20Sopenharmony_ci	int val;
20388c2ecf20Sopenharmony_ci
20398c2ecf20Sopenharmony_ci	if (!snd_hdsp_use_is_exclusive(hdsp))
20408c2ecf20Sopenharmony_ci		return -EBUSY;
20418c2ecf20Sopenharmony_ci	val = ucontrol->value.enumerated.item[0];
20428c2ecf20Sopenharmony_ci	if (val < 0) val = 0;
20438c2ecf20Sopenharmony_ci	if (hdsp->io_type == H9632) {
20448c2ecf20Sopenharmony_ci		if (val > 9)
20458c2ecf20Sopenharmony_ci			val = 9;
20468c2ecf20Sopenharmony_ci	} else {
20478c2ecf20Sopenharmony_ci		if (val > 6)
20488c2ecf20Sopenharmony_ci			val = 6;
20498c2ecf20Sopenharmony_ci	}
20508c2ecf20Sopenharmony_ci	spin_lock_irq(&hdsp->lock);
20518c2ecf20Sopenharmony_ci	if (val != hdsp_clock_source(hdsp))
20528c2ecf20Sopenharmony_ci		change = (hdsp_set_clock_source(hdsp, val) == 0) ? 1 : 0;
20538c2ecf20Sopenharmony_ci	else
20548c2ecf20Sopenharmony_ci		change = 0;
20558c2ecf20Sopenharmony_ci	spin_unlock_irq(&hdsp->lock);
20568c2ecf20Sopenharmony_ci	return change;
20578c2ecf20Sopenharmony_ci}
20588c2ecf20Sopenharmony_ci
20598c2ecf20Sopenharmony_ci#define snd_hdsp_info_clock_source_lock		snd_ctl_boolean_mono_info
20608c2ecf20Sopenharmony_ci
20618c2ecf20Sopenharmony_cistatic int snd_hdsp_get_clock_source_lock(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
20628c2ecf20Sopenharmony_ci{
20638c2ecf20Sopenharmony_ci	struct hdsp *hdsp = snd_kcontrol_chip(kcontrol);
20648c2ecf20Sopenharmony_ci
20658c2ecf20Sopenharmony_ci	ucontrol->value.integer.value[0] = hdsp->clock_source_locked;
20668c2ecf20Sopenharmony_ci	return 0;
20678c2ecf20Sopenharmony_ci}
20688c2ecf20Sopenharmony_ci
20698c2ecf20Sopenharmony_cistatic int snd_hdsp_put_clock_source_lock(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
20708c2ecf20Sopenharmony_ci{
20718c2ecf20Sopenharmony_ci	struct hdsp *hdsp = snd_kcontrol_chip(kcontrol);
20728c2ecf20Sopenharmony_ci	int change;
20738c2ecf20Sopenharmony_ci
20748c2ecf20Sopenharmony_ci	change = (int)ucontrol->value.integer.value[0] != hdsp->clock_source_locked;
20758c2ecf20Sopenharmony_ci	if (change)
20768c2ecf20Sopenharmony_ci		hdsp->clock_source_locked = !!ucontrol->value.integer.value[0];
20778c2ecf20Sopenharmony_ci	return change;
20788c2ecf20Sopenharmony_ci}
20798c2ecf20Sopenharmony_ci
20808c2ecf20Sopenharmony_ci#define HDSP_DA_GAIN(xname, xindex) \
20818c2ecf20Sopenharmony_ci{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
20828c2ecf20Sopenharmony_ci  .name = xname, \
20838c2ecf20Sopenharmony_ci  .index = xindex, \
20848c2ecf20Sopenharmony_ci  .info = snd_hdsp_info_da_gain, \
20858c2ecf20Sopenharmony_ci  .get = snd_hdsp_get_da_gain, \
20868c2ecf20Sopenharmony_ci  .put = snd_hdsp_put_da_gain \
20878c2ecf20Sopenharmony_ci}
20888c2ecf20Sopenharmony_ci
20898c2ecf20Sopenharmony_cistatic int hdsp_da_gain(struct hdsp *hdsp)
20908c2ecf20Sopenharmony_ci{
20918c2ecf20Sopenharmony_ci	switch (hdsp->control_register & HDSP_DAGainMask) {
20928c2ecf20Sopenharmony_ci	case HDSP_DAGainHighGain:
20938c2ecf20Sopenharmony_ci		return 0;
20948c2ecf20Sopenharmony_ci	case HDSP_DAGainPlus4dBu:
20958c2ecf20Sopenharmony_ci		return 1;
20968c2ecf20Sopenharmony_ci	case HDSP_DAGainMinus10dBV:
20978c2ecf20Sopenharmony_ci		return 2;
20988c2ecf20Sopenharmony_ci	default:
20998c2ecf20Sopenharmony_ci		return 1;
21008c2ecf20Sopenharmony_ci	}
21018c2ecf20Sopenharmony_ci}
21028c2ecf20Sopenharmony_ci
21038c2ecf20Sopenharmony_cistatic int hdsp_set_da_gain(struct hdsp *hdsp, int mode)
21048c2ecf20Sopenharmony_ci{
21058c2ecf20Sopenharmony_ci	hdsp->control_register &= ~HDSP_DAGainMask;
21068c2ecf20Sopenharmony_ci	switch (mode) {
21078c2ecf20Sopenharmony_ci	case 0:
21088c2ecf20Sopenharmony_ci		hdsp->control_register |= HDSP_DAGainHighGain;
21098c2ecf20Sopenharmony_ci		break;
21108c2ecf20Sopenharmony_ci	case 1:
21118c2ecf20Sopenharmony_ci		hdsp->control_register |= HDSP_DAGainPlus4dBu;
21128c2ecf20Sopenharmony_ci		break;
21138c2ecf20Sopenharmony_ci	case 2:
21148c2ecf20Sopenharmony_ci		hdsp->control_register |= HDSP_DAGainMinus10dBV;
21158c2ecf20Sopenharmony_ci		break;
21168c2ecf20Sopenharmony_ci	default:
21178c2ecf20Sopenharmony_ci		return -1;
21188c2ecf20Sopenharmony_ci
21198c2ecf20Sopenharmony_ci	}
21208c2ecf20Sopenharmony_ci	hdsp_write(hdsp, HDSP_controlRegister, hdsp->control_register);
21218c2ecf20Sopenharmony_ci	return 0;
21228c2ecf20Sopenharmony_ci}
21238c2ecf20Sopenharmony_ci
21248c2ecf20Sopenharmony_cistatic int snd_hdsp_info_da_gain(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
21258c2ecf20Sopenharmony_ci{
21268c2ecf20Sopenharmony_ci	static const char * const texts[] = {"Hi Gain", "+4 dBu", "-10 dbV"};
21278c2ecf20Sopenharmony_ci
21288c2ecf20Sopenharmony_ci	return snd_ctl_enum_info(uinfo, 1, 3, texts);
21298c2ecf20Sopenharmony_ci}
21308c2ecf20Sopenharmony_ci
21318c2ecf20Sopenharmony_cistatic int snd_hdsp_get_da_gain(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
21328c2ecf20Sopenharmony_ci{
21338c2ecf20Sopenharmony_ci	struct hdsp *hdsp = snd_kcontrol_chip(kcontrol);
21348c2ecf20Sopenharmony_ci
21358c2ecf20Sopenharmony_ci	ucontrol->value.enumerated.item[0] = hdsp_da_gain(hdsp);
21368c2ecf20Sopenharmony_ci	return 0;
21378c2ecf20Sopenharmony_ci}
21388c2ecf20Sopenharmony_ci
21398c2ecf20Sopenharmony_cistatic int snd_hdsp_put_da_gain(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
21408c2ecf20Sopenharmony_ci{
21418c2ecf20Sopenharmony_ci	struct hdsp *hdsp = snd_kcontrol_chip(kcontrol);
21428c2ecf20Sopenharmony_ci	int change;
21438c2ecf20Sopenharmony_ci	int val;
21448c2ecf20Sopenharmony_ci
21458c2ecf20Sopenharmony_ci	if (!snd_hdsp_use_is_exclusive(hdsp))
21468c2ecf20Sopenharmony_ci		return -EBUSY;
21478c2ecf20Sopenharmony_ci	val = ucontrol->value.enumerated.item[0];
21488c2ecf20Sopenharmony_ci	if (val < 0) val = 0;
21498c2ecf20Sopenharmony_ci	if (val > 2) val = 2;
21508c2ecf20Sopenharmony_ci	spin_lock_irq(&hdsp->lock);
21518c2ecf20Sopenharmony_ci	if (val != hdsp_da_gain(hdsp))
21528c2ecf20Sopenharmony_ci		change = (hdsp_set_da_gain(hdsp, val) == 0) ? 1 : 0;
21538c2ecf20Sopenharmony_ci	else
21548c2ecf20Sopenharmony_ci		change = 0;
21558c2ecf20Sopenharmony_ci	spin_unlock_irq(&hdsp->lock);
21568c2ecf20Sopenharmony_ci	return change;
21578c2ecf20Sopenharmony_ci}
21588c2ecf20Sopenharmony_ci
21598c2ecf20Sopenharmony_ci#define HDSP_AD_GAIN(xname, xindex) \
21608c2ecf20Sopenharmony_ci{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
21618c2ecf20Sopenharmony_ci  .name = xname, \
21628c2ecf20Sopenharmony_ci  .index = xindex, \
21638c2ecf20Sopenharmony_ci  .info = snd_hdsp_info_ad_gain, \
21648c2ecf20Sopenharmony_ci  .get = snd_hdsp_get_ad_gain, \
21658c2ecf20Sopenharmony_ci  .put = snd_hdsp_put_ad_gain \
21668c2ecf20Sopenharmony_ci}
21678c2ecf20Sopenharmony_ci
21688c2ecf20Sopenharmony_cistatic int hdsp_ad_gain(struct hdsp *hdsp)
21698c2ecf20Sopenharmony_ci{
21708c2ecf20Sopenharmony_ci	switch (hdsp->control_register & HDSP_ADGainMask) {
21718c2ecf20Sopenharmony_ci	case HDSP_ADGainMinus10dBV:
21728c2ecf20Sopenharmony_ci		return 0;
21738c2ecf20Sopenharmony_ci	case HDSP_ADGainPlus4dBu:
21748c2ecf20Sopenharmony_ci		return 1;
21758c2ecf20Sopenharmony_ci	case HDSP_ADGainLowGain:
21768c2ecf20Sopenharmony_ci		return 2;
21778c2ecf20Sopenharmony_ci	default:
21788c2ecf20Sopenharmony_ci		return 1;
21798c2ecf20Sopenharmony_ci	}
21808c2ecf20Sopenharmony_ci}
21818c2ecf20Sopenharmony_ci
21828c2ecf20Sopenharmony_cistatic int hdsp_set_ad_gain(struct hdsp *hdsp, int mode)
21838c2ecf20Sopenharmony_ci{
21848c2ecf20Sopenharmony_ci	hdsp->control_register &= ~HDSP_ADGainMask;
21858c2ecf20Sopenharmony_ci	switch (mode) {
21868c2ecf20Sopenharmony_ci	case 0:
21878c2ecf20Sopenharmony_ci		hdsp->control_register |= HDSP_ADGainMinus10dBV;
21888c2ecf20Sopenharmony_ci		break;
21898c2ecf20Sopenharmony_ci	case 1:
21908c2ecf20Sopenharmony_ci		hdsp->control_register |= HDSP_ADGainPlus4dBu;
21918c2ecf20Sopenharmony_ci		break;
21928c2ecf20Sopenharmony_ci	case 2:
21938c2ecf20Sopenharmony_ci		hdsp->control_register |= HDSP_ADGainLowGain;
21948c2ecf20Sopenharmony_ci		break;
21958c2ecf20Sopenharmony_ci	default:
21968c2ecf20Sopenharmony_ci		return -1;
21978c2ecf20Sopenharmony_ci
21988c2ecf20Sopenharmony_ci	}
21998c2ecf20Sopenharmony_ci	hdsp_write(hdsp, HDSP_controlRegister, hdsp->control_register);
22008c2ecf20Sopenharmony_ci	return 0;
22018c2ecf20Sopenharmony_ci}
22028c2ecf20Sopenharmony_ci
22038c2ecf20Sopenharmony_cistatic int snd_hdsp_info_ad_gain(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
22048c2ecf20Sopenharmony_ci{
22058c2ecf20Sopenharmony_ci	static const char * const texts[] = {"-10 dBV", "+4 dBu", "Lo Gain"};
22068c2ecf20Sopenharmony_ci
22078c2ecf20Sopenharmony_ci	return snd_ctl_enum_info(uinfo, 1, 3, texts);
22088c2ecf20Sopenharmony_ci}
22098c2ecf20Sopenharmony_ci
22108c2ecf20Sopenharmony_cistatic int snd_hdsp_get_ad_gain(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
22118c2ecf20Sopenharmony_ci{
22128c2ecf20Sopenharmony_ci	struct hdsp *hdsp = snd_kcontrol_chip(kcontrol);
22138c2ecf20Sopenharmony_ci
22148c2ecf20Sopenharmony_ci	ucontrol->value.enumerated.item[0] = hdsp_ad_gain(hdsp);
22158c2ecf20Sopenharmony_ci	return 0;
22168c2ecf20Sopenharmony_ci}
22178c2ecf20Sopenharmony_ci
22188c2ecf20Sopenharmony_cistatic int snd_hdsp_put_ad_gain(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
22198c2ecf20Sopenharmony_ci{
22208c2ecf20Sopenharmony_ci	struct hdsp *hdsp = snd_kcontrol_chip(kcontrol);
22218c2ecf20Sopenharmony_ci	int change;
22228c2ecf20Sopenharmony_ci	int val;
22238c2ecf20Sopenharmony_ci
22248c2ecf20Sopenharmony_ci	if (!snd_hdsp_use_is_exclusive(hdsp))
22258c2ecf20Sopenharmony_ci		return -EBUSY;
22268c2ecf20Sopenharmony_ci	val = ucontrol->value.enumerated.item[0];
22278c2ecf20Sopenharmony_ci	if (val < 0) val = 0;
22288c2ecf20Sopenharmony_ci	if (val > 2) val = 2;
22298c2ecf20Sopenharmony_ci	spin_lock_irq(&hdsp->lock);
22308c2ecf20Sopenharmony_ci	if (val != hdsp_ad_gain(hdsp))
22318c2ecf20Sopenharmony_ci		change = (hdsp_set_ad_gain(hdsp, val) == 0) ? 1 : 0;
22328c2ecf20Sopenharmony_ci	else
22338c2ecf20Sopenharmony_ci		change = 0;
22348c2ecf20Sopenharmony_ci	spin_unlock_irq(&hdsp->lock);
22358c2ecf20Sopenharmony_ci	return change;
22368c2ecf20Sopenharmony_ci}
22378c2ecf20Sopenharmony_ci
22388c2ecf20Sopenharmony_ci#define HDSP_PHONE_GAIN(xname, xindex) \
22398c2ecf20Sopenharmony_ci{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
22408c2ecf20Sopenharmony_ci  .name = xname, \
22418c2ecf20Sopenharmony_ci  .index = xindex, \
22428c2ecf20Sopenharmony_ci  .info = snd_hdsp_info_phone_gain, \
22438c2ecf20Sopenharmony_ci  .get = snd_hdsp_get_phone_gain, \
22448c2ecf20Sopenharmony_ci  .put = snd_hdsp_put_phone_gain \
22458c2ecf20Sopenharmony_ci}
22468c2ecf20Sopenharmony_ci
22478c2ecf20Sopenharmony_cistatic int hdsp_phone_gain(struct hdsp *hdsp)
22488c2ecf20Sopenharmony_ci{
22498c2ecf20Sopenharmony_ci	switch (hdsp->control_register & HDSP_PhoneGainMask) {
22508c2ecf20Sopenharmony_ci	case HDSP_PhoneGain0dB:
22518c2ecf20Sopenharmony_ci		return 0;
22528c2ecf20Sopenharmony_ci	case HDSP_PhoneGainMinus6dB:
22538c2ecf20Sopenharmony_ci		return 1;
22548c2ecf20Sopenharmony_ci	case HDSP_PhoneGainMinus12dB:
22558c2ecf20Sopenharmony_ci		return 2;
22568c2ecf20Sopenharmony_ci	default:
22578c2ecf20Sopenharmony_ci		return 0;
22588c2ecf20Sopenharmony_ci	}
22598c2ecf20Sopenharmony_ci}
22608c2ecf20Sopenharmony_ci
22618c2ecf20Sopenharmony_cistatic int hdsp_set_phone_gain(struct hdsp *hdsp, int mode)
22628c2ecf20Sopenharmony_ci{
22638c2ecf20Sopenharmony_ci	hdsp->control_register &= ~HDSP_PhoneGainMask;
22648c2ecf20Sopenharmony_ci	switch (mode) {
22658c2ecf20Sopenharmony_ci	case 0:
22668c2ecf20Sopenharmony_ci		hdsp->control_register |= HDSP_PhoneGain0dB;
22678c2ecf20Sopenharmony_ci		break;
22688c2ecf20Sopenharmony_ci	case 1:
22698c2ecf20Sopenharmony_ci		hdsp->control_register |= HDSP_PhoneGainMinus6dB;
22708c2ecf20Sopenharmony_ci		break;
22718c2ecf20Sopenharmony_ci	case 2:
22728c2ecf20Sopenharmony_ci		hdsp->control_register |= HDSP_PhoneGainMinus12dB;
22738c2ecf20Sopenharmony_ci		break;
22748c2ecf20Sopenharmony_ci	default:
22758c2ecf20Sopenharmony_ci		return -1;
22768c2ecf20Sopenharmony_ci
22778c2ecf20Sopenharmony_ci	}
22788c2ecf20Sopenharmony_ci	hdsp_write(hdsp, HDSP_controlRegister, hdsp->control_register);
22798c2ecf20Sopenharmony_ci	return 0;
22808c2ecf20Sopenharmony_ci}
22818c2ecf20Sopenharmony_ci
22828c2ecf20Sopenharmony_cistatic int snd_hdsp_info_phone_gain(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
22838c2ecf20Sopenharmony_ci{
22848c2ecf20Sopenharmony_ci	static const char * const texts[] = {"0 dB", "-6 dB", "-12 dB"};
22858c2ecf20Sopenharmony_ci
22868c2ecf20Sopenharmony_ci	return snd_ctl_enum_info(uinfo, 1, 3, texts);
22878c2ecf20Sopenharmony_ci}
22888c2ecf20Sopenharmony_ci
22898c2ecf20Sopenharmony_cistatic int snd_hdsp_get_phone_gain(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
22908c2ecf20Sopenharmony_ci{
22918c2ecf20Sopenharmony_ci	struct hdsp *hdsp = snd_kcontrol_chip(kcontrol);
22928c2ecf20Sopenharmony_ci
22938c2ecf20Sopenharmony_ci	ucontrol->value.enumerated.item[0] = hdsp_phone_gain(hdsp);
22948c2ecf20Sopenharmony_ci	return 0;
22958c2ecf20Sopenharmony_ci}
22968c2ecf20Sopenharmony_ci
22978c2ecf20Sopenharmony_cistatic int snd_hdsp_put_phone_gain(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
22988c2ecf20Sopenharmony_ci{
22998c2ecf20Sopenharmony_ci	struct hdsp *hdsp = snd_kcontrol_chip(kcontrol);
23008c2ecf20Sopenharmony_ci	int change;
23018c2ecf20Sopenharmony_ci	int val;
23028c2ecf20Sopenharmony_ci
23038c2ecf20Sopenharmony_ci	if (!snd_hdsp_use_is_exclusive(hdsp))
23048c2ecf20Sopenharmony_ci		return -EBUSY;
23058c2ecf20Sopenharmony_ci	val = ucontrol->value.enumerated.item[0];
23068c2ecf20Sopenharmony_ci	if (val < 0) val = 0;
23078c2ecf20Sopenharmony_ci	if (val > 2) val = 2;
23088c2ecf20Sopenharmony_ci	spin_lock_irq(&hdsp->lock);
23098c2ecf20Sopenharmony_ci	if (val != hdsp_phone_gain(hdsp))
23108c2ecf20Sopenharmony_ci		change = (hdsp_set_phone_gain(hdsp, val) == 0) ? 1 : 0;
23118c2ecf20Sopenharmony_ci	else
23128c2ecf20Sopenharmony_ci		change = 0;
23138c2ecf20Sopenharmony_ci	spin_unlock_irq(&hdsp->lock);
23148c2ecf20Sopenharmony_ci	return change;
23158c2ecf20Sopenharmony_ci}
23168c2ecf20Sopenharmony_ci
23178c2ecf20Sopenharmony_ci#define HDSP_PREF_SYNC_REF(xname, xindex) \
23188c2ecf20Sopenharmony_ci{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
23198c2ecf20Sopenharmony_ci  .name = xname, \
23208c2ecf20Sopenharmony_ci  .index = xindex, \
23218c2ecf20Sopenharmony_ci  .info = snd_hdsp_info_pref_sync_ref, \
23228c2ecf20Sopenharmony_ci  .get = snd_hdsp_get_pref_sync_ref, \
23238c2ecf20Sopenharmony_ci  .put = snd_hdsp_put_pref_sync_ref \
23248c2ecf20Sopenharmony_ci}
23258c2ecf20Sopenharmony_ci
23268c2ecf20Sopenharmony_cistatic int hdsp_pref_sync_ref(struct hdsp *hdsp)
23278c2ecf20Sopenharmony_ci{
23288c2ecf20Sopenharmony_ci	/* Notice that this looks at the requested sync source,
23298c2ecf20Sopenharmony_ci	   not the one actually in use.
23308c2ecf20Sopenharmony_ci	*/
23318c2ecf20Sopenharmony_ci
23328c2ecf20Sopenharmony_ci	switch (hdsp->control_register & HDSP_SyncRefMask) {
23338c2ecf20Sopenharmony_ci	case HDSP_SyncRef_ADAT1:
23348c2ecf20Sopenharmony_ci		return HDSP_SYNC_FROM_ADAT1;
23358c2ecf20Sopenharmony_ci	case HDSP_SyncRef_ADAT2:
23368c2ecf20Sopenharmony_ci		return HDSP_SYNC_FROM_ADAT2;
23378c2ecf20Sopenharmony_ci	case HDSP_SyncRef_ADAT3:
23388c2ecf20Sopenharmony_ci		return HDSP_SYNC_FROM_ADAT3;
23398c2ecf20Sopenharmony_ci	case HDSP_SyncRef_SPDIF:
23408c2ecf20Sopenharmony_ci		return HDSP_SYNC_FROM_SPDIF;
23418c2ecf20Sopenharmony_ci	case HDSP_SyncRef_WORD:
23428c2ecf20Sopenharmony_ci		return HDSP_SYNC_FROM_WORD;
23438c2ecf20Sopenharmony_ci	case HDSP_SyncRef_ADAT_SYNC:
23448c2ecf20Sopenharmony_ci		return HDSP_SYNC_FROM_ADAT_SYNC;
23458c2ecf20Sopenharmony_ci	default:
23468c2ecf20Sopenharmony_ci		return HDSP_SYNC_FROM_WORD;
23478c2ecf20Sopenharmony_ci	}
23488c2ecf20Sopenharmony_ci	return 0;
23498c2ecf20Sopenharmony_ci}
23508c2ecf20Sopenharmony_ci
23518c2ecf20Sopenharmony_cistatic int hdsp_set_pref_sync_ref(struct hdsp *hdsp, int pref)
23528c2ecf20Sopenharmony_ci{
23538c2ecf20Sopenharmony_ci	hdsp->control_register &= ~HDSP_SyncRefMask;
23548c2ecf20Sopenharmony_ci	switch (pref) {
23558c2ecf20Sopenharmony_ci	case HDSP_SYNC_FROM_ADAT1:
23568c2ecf20Sopenharmony_ci		hdsp->control_register &= ~HDSP_SyncRefMask; /* clear SyncRef bits */
23578c2ecf20Sopenharmony_ci		break;
23588c2ecf20Sopenharmony_ci	case HDSP_SYNC_FROM_ADAT2:
23598c2ecf20Sopenharmony_ci		hdsp->control_register |= HDSP_SyncRef_ADAT2;
23608c2ecf20Sopenharmony_ci		break;
23618c2ecf20Sopenharmony_ci	case HDSP_SYNC_FROM_ADAT3:
23628c2ecf20Sopenharmony_ci		hdsp->control_register |= HDSP_SyncRef_ADAT3;
23638c2ecf20Sopenharmony_ci		break;
23648c2ecf20Sopenharmony_ci	case HDSP_SYNC_FROM_SPDIF:
23658c2ecf20Sopenharmony_ci		hdsp->control_register |= HDSP_SyncRef_SPDIF;
23668c2ecf20Sopenharmony_ci		break;
23678c2ecf20Sopenharmony_ci	case HDSP_SYNC_FROM_WORD:
23688c2ecf20Sopenharmony_ci		hdsp->control_register |= HDSP_SyncRef_WORD;
23698c2ecf20Sopenharmony_ci		break;
23708c2ecf20Sopenharmony_ci	case HDSP_SYNC_FROM_ADAT_SYNC:
23718c2ecf20Sopenharmony_ci		hdsp->control_register |= HDSP_SyncRef_ADAT_SYNC;
23728c2ecf20Sopenharmony_ci		break;
23738c2ecf20Sopenharmony_ci	default:
23748c2ecf20Sopenharmony_ci		return -1;
23758c2ecf20Sopenharmony_ci	}
23768c2ecf20Sopenharmony_ci	hdsp_write(hdsp, HDSP_controlRegister, hdsp->control_register);
23778c2ecf20Sopenharmony_ci	return 0;
23788c2ecf20Sopenharmony_ci}
23798c2ecf20Sopenharmony_ci
23808c2ecf20Sopenharmony_cistatic int snd_hdsp_info_pref_sync_ref(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
23818c2ecf20Sopenharmony_ci{
23828c2ecf20Sopenharmony_ci	static const char * const texts[] = {
23838c2ecf20Sopenharmony_ci		"Word", "IEC958", "ADAT1", "ADAT Sync", "ADAT2", "ADAT3"
23848c2ecf20Sopenharmony_ci	};
23858c2ecf20Sopenharmony_ci	struct hdsp *hdsp = snd_kcontrol_chip(kcontrol);
23868c2ecf20Sopenharmony_ci	int num_items;
23878c2ecf20Sopenharmony_ci
23888c2ecf20Sopenharmony_ci	switch (hdsp->io_type) {
23898c2ecf20Sopenharmony_ci	case Digiface:
23908c2ecf20Sopenharmony_ci	case H9652:
23918c2ecf20Sopenharmony_ci		num_items = 6;
23928c2ecf20Sopenharmony_ci		break;
23938c2ecf20Sopenharmony_ci	case Multiface:
23948c2ecf20Sopenharmony_ci		num_items = 4;
23958c2ecf20Sopenharmony_ci		break;
23968c2ecf20Sopenharmony_ci	case H9632:
23978c2ecf20Sopenharmony_ci		num_items = 3;
23988c2ecf20Sopenharmony_ci		break;
23998c2ecf20Sopenharmony_ci	default:
24008c2ecf20Sopenharmony_ci		return -EINVAL;
24018c2ecf20Sopenharmony_ci	}
24028c2ecf20Sopenharmony_ci
24038c2ecf20Sopenharmony_ci	return snd_ctl_enum_info(uinfo, 1, num_items, texts);
24048c2ecf20Sopenharmony_ci}
24058c2ecf20Sopenharmony_ci
24068c2ecf20Sopenharmony_cistatic int snd_hdsp_get_pref_sync_ref(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
24078c2ecf20Sopenharmony_ci{
24088c2ecf20Sopenharmony_ci	struct hdsp *hdsp = snd_kcontrol_chip(kcontrol);
24098c2ecf20Sopenharmony_ci
24108c2ecf20Sopenharmony_ci	ucontrol->value.enumerated.item[0] = hdsp_pref_sync_ref(hdsp);
24118c2ecf20Sopenharmony_ci	return 0;
24128c2ecf20Sopenharmony_ci}
24138c2ecf20Sopenharmony_ci
24148c2ecf20Sopenharmony_cistatic int snd_hdsp_put_pref_sync_ref(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
24158c2ecf20Sopenharmony_ci{
24168c2ecf20Sopenharmony_ci	struct hdsp *hdsp = snd_kcontrol_chip(kcontrol);
24178c2ecf20Sopenharmony_ci	int change, max;
24188c2ecf20Sopenharmony_ci	unsigned int val;
24198c2ecf20Sopenharmony_ci
24208c2ecf20Sopenharmony_ci	if (!snd_hdsp_use_is_exclusive(hdsp))
24218c2ecf20Sopenharmony_ci		return -EBUSY;
24228c2ecf20Sopenharmony_ci
24238c2ecf20Sopenharmony_ci	switch (hdsp->io_type) {
24248c2ecf20Sopenharmony_ci	case Digiface:
24258c2ecf20Sopenharmony_ci	case H9652:
24268c2ecf20Sopenharmony_ci		max = 6;
24278c2ecf20Sopenharmony_ci		break;
24288c2ecf20Sopenharmony_ci	case Multiface:
24298c2ecf20Sopenharmony_ci		max = 4;
24308c2ecf20Sopenharmony_ci		break;
24318c2ecf20Sopenharmony_ci	case H9632:
24328c2ecf20Sopenharmony_ci		max = 3;
24338c2ecf20Sopenharmony_ci		break;
24348c2ecf20Sopenharmony_ci	default:
24358c2ecf20Sopenharmony_ci		return -EIO;
24368c2ecf20Sopenharmony_ci	}
24378c2ecf20Sopenharmony_ci
24388c2ecf20Sopenharmony_ci	val = ucontrol->value.enumerated.item[0] % max;
24398c2ecf20Sopenharmony_ci	spin_lock_irq(&hdsp->lock);
24408c2ecf20Sopenharmony_ci	change = (int)val != hdsp_pref_sync_ref(hdsp);
24418c2ecf20Sopenharmony_ci	hdsp_set_pref_sync_ref(hdsp, val);
24428c2ecf20Sopenharmony_ci	spin_unlock_irq(&hdsp->lock);
24438c2ecf20Sopenharmony_ci	return change;
24448c2ecf20Sopenharmony_ci}
24458c2ecf20Sopenharmony_ci
24468c2ecf20Sopenharmony_ci#define HDSP_AUTOSYNC_REF(xname, xindex) \
24478c2ecf20Sopenharmony_ci{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
24488c2ecf20Sopenharmony_ci  .name = xname, \
24498c2ecf20Sopenharmony_ci  .index = xindex, \
24508c2ecf20Sopenharmony_ci  .access = SNDRV_CTL_ELEM_ACCESS_READ, \
24518c2ecf20Sopenharmony_ci  .info = snd_hdsp_info_autosync_ref, \
24528c2ecf20Sopenharmony_ci  .get = snd_hdsp_get_autosync_ref, \
24538c2ecf20Sopenharmony_ci}
24548c2ecf20Sopenharmony_ci
24558c2ecf20Sopenharmony_cistatic int hdsp_autosync_ref(struct hdsp *hdsp)
24568c2ecf20Sopenharmony_ci{
24578c2ecf20Sopenharmony_ci	/* This looks at the autosync selected sync reference */
24588c2ecf20Sopenharmony_ci	unsigned int status2 = hdsp_read(hdsp, HDSP_status2Register);
24598c2ecf20Sopenharmony_ci
24608c2ecf20Sopenharmony_ci	switch (status2 & HDSP_SelSyncRefMask) {
24618c2ecf20Sopenharmony_ci	case HDSP_SelSyncRef_WORD:
24628c2ecf20Sopenharmony_ci		return HDSP_AUTOSYNC_FROM_WORD;
24638c2ecf20Sopenharmony_ci	case HDSP_SelSyncRef_ADAT_SYNC:
24648c2ecf20Sopenharmony_ci		return HDSP_AUTOSYNC_FROM_ADAT_SYNC;
24658c2ecf20Sopenharmony_ci	case HDSP_SelSyncRef_SPDIF:
24668c2ecf20Sopenharmony_ci		return HDSP_AUTOSYNC_FROM_SPDIF;
24678c2ecf20Sopenharmony_ci	case HDSP_SelSyncRefMask:
24688c2ecf20Sopenharmony_ci		return HDSP_AUTOSYNC_FROM_NONE;
24698c2ecf20Sopenharmony_ci	case HDSP_SelSyncRef_ADAT1:
24708c2ecf20Sopenharmony_ci		return HDSP_AUTOSYNC_FROM_ADAT1;
24718c2ecf20Sopenharmony_ci	case HDSP_SelSyncRef_ADAT2:
24728c2ecf20Sopenharmony_ci		return HDSP_AUTOSYNC_FROM_ADAT2;
24738c2ecf20Sopenharmony_ci	case HDSP_SelSyncRef_ADAT3:
24748c2ecf20Sopenharmony_ci		return HDSP_AUTOSYNC_FROM_ADAT3;
24758c2ecf20Sopenharmony_ci	default:
24768c2ecf20Sopenharmony_ci		return HDSP_AUTOSYNC_FROM_WORD;
24778c2ecf20Sopenharmony_ci	}
24788c2ecf20Sopenharmony_ci	return 0;
24798c2ecf20Sopenharmony_ci}
24808c2ecf20Sopenharmony_ci
24818c2ecf20Sopenharmony_cistatic int snd_hdsp_info_autosync_ref(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
24828c2ecf20Sopenharmony_ci{
24838c2ecf20Sopenharmony_ci	static const char * const texts[] = {
24848c2ecf20Sopenharmony_ci		"Word", "ADAT Sync", "IEC958", "None", "ADAT1", "ADAT2", "ADAT3"
24858c2ecf20Sopenharmony_ci	};
24868c2ecf20Sopenharmony_ci
24878c2ecf20Sopenharmony_ci	return snd_ctl_enum_info(uinfo, 1, 7, texts);
24888c2ecf20Sopenharmony_ci}
24898c2ecf20Sopenharmony_ci
24908c2ecf20Sopenharmony_cistatic int snd_hdsp_get_autosync_ref(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
24918c2ecf20Sopenharmony_ci{
24928c2ecf20Sopenharmony_ci	struct hdsp *hdsp = snd_kcontrol_chip(kcontrol);
24938c2ecf20Sopenharmony_ci
24948c2ecf20Sopenharmony_ci	ucontrol->value.enumerated.item[0] = hdsp_autosync_ref(hdsp);
24958c2ecf20Sopenharmony_ci	return 0;
24968c2ecf20Sopenharmony_ci}
24978c2ecf20Sopenharmony_ci
24988c2ecf20Sopenharmony_ci#define HDSP_PRECISE_POINTER(xname, xindex) \
24998c2ecf20Sopenharmony_ci{ .iface = SNDRV_CTL_ELEM_IFACE_CARD, \
25008c2ecf20Sopenharmony_ci  .name = xname, \
25018c2ecf20Sopenharmony_ci  .index = xindex, \
25028c2ecf20Sopenharmony_ci  .info = snd_hdsp_info_precise_pointer, \
25038c2ecf20Sopenharmony_ci  .get = snd_hdsp_get_precise_pointer, \
25048c2ecf20Sopenharmony_ci  .put = snd_hdsp_put_precise_pointer \
25058c2ecf20Sopenharmony_ci}
25068c2ecf20Sopenharmony_ci
25078c2ecf20Sopenharmony_cistatic int hdsp_set_precise_pointer(struct hdsp *hdsp, int precise)
25088c2ecf20Sopenharmony_ci{
25098c2ecf20Sopenharmony_ci	if (precise)
25108c2ecf20Sopenharmony_ci		hdsp->precise_ptr = 1;
25118c2ecf20Sopenharmony_ci	else
25128c2ecf20Sopenharmony_ci		hdsp->precise_ptr = 0;
25138c2ecf20Sopenharmony_ci	return 0;
25148c2ecf20Sopenharmony_ci}
25158c2ecf20Sopenharmony_ci
25168c2ecf20Sopenharmony_ci#define snd_hdsp_info_precise_pointer		snd_ctl_boolean_mono_info
25178c2ecf20Sopenharmony_ci
25188c2ecf20Sopenharmony_cistatic int snd_hdsp_get_precise_pointer(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
25198c2ecf20Sopenharmony_ci{
25208c2ecf20Sopenharmony_ci	struct hdsp *hdsp = snd_kcontrol_chip(kcontrol);
25218c2ecf20Sopenharmony_ci
25228c2ecf20Sopenharmony_ci	spin_lock_irq(&hdsp->lock);
25238c2ecf20Sopenharmony_ci	ucontrol->value.integer.value[0] = hdsp->precise_ptr;
25248c2ecf20Sopenharmony_ci	spin_unlock_irq(&hdsp->lock);
25258c2ecf20Sopenharmony_ci	return 0;
25268c2ecf20Sopenharmony_ci}
25278c2ecf20Sopenharmony_ci
25288c2ecf20Sopenharmony_cistatic int snd_hdsp_put_precise_pointer(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
25298c2ecf20Sopenharmony_ci{
25308c2ecf20Sopenharmony_ci	struct hdsp *hdsp = snd_kcontrol_chip(kcontrol);
25318c2ecf20Sopenharmony_ci	int change;
25328c2ecf20Sopenharmony_ci	unsigned int val;
25338c2ecf20Sopenharmony_ci
25348c2ecf20Sopenharmony_ci	if (!snd_hdsp_use_is_exclusive(hdsp))
25358c2ecf20Sopenharmony_ci		return -EBUSY;
25368c2ecf20Sopenharmony_ci	val = ucontrol->value.integer.value[0] & 1;
25378c2ecf20Sopenharmony_ci	spin_lock_irq(&hdsp->lock);
25388c2ecf20Sopenharmony_ci	change = (int)val != hdsp->precise_ptr;
25398c2ecf20Sopenharmony_ci	hdsp_set_precise_pointer(hdsp, val);
25408c2ecf20Sopenharmony_ci	spin_unlock_irq(&hdsp->lock);
25418c2ecf20Sopenharmony_ci	return change;
25428c2ecf20Sopenharmony_ci}
25438c2ecf20Sopenharmony_ci
25448c2ecf20Sopenharmony_ci#define HDSP_USE_MIDI_WORK(xname, xindex) \
25458c2ecf20Sopenharmony_ci{ .iface = SNDRV_CTL_ELEM_IFACE_CARD, \
25468c2ecf20Sopenharmony_ci  .name = xname, \
25478c2ecf20Sopenharmony_ci  .index = xindex, \
25488c2ecf20Sopenharmony_ci  .info = snd_hdsp_info_use_midi_work, \
25498c2ecf20Sopenharmony_ci  .get = snd_hdsp_get_use_midi_work, \
25508c2ecf20Sopenharmony_ci  .put = snd_hdsp_put_use_midi_work \
25518c2ecf20Sopenharmony_ci}
25528c2ecf20Sopenharmony_ci
25538c2ecf20Sopenharmony_cistatic int hdsp_set_use_midi_work(struct hdsp *hdsp, int use_work)
25548c2ecf20Sopenharmony_ci{
25558c2ecf20Sopenharmony_ci	if (use_work)
25568c2ecf20Sopenharmony_ci		hdsp->use_midi_work = 1;
25578c2ecf20Sopenharmony_ci	else
25588c2ecf20Sopenharmony_ci		hdsp->use_midi_work = 0;
25598c2ecf20Sopenharmony_ci	return 0;
25608c2ecf20Sopenharmony_ci}
25618c2ecf20Sopenharmony_ci
25628c2ecf20Sopenharmony_ci#define snd_hdsp_info_use_midi_work		snd_ctl_boolean_mono_info
25638c2ecf20Sopenharmony_ci
25648c2ecf20Sopenharmony_cistatic int snd_hdsp_get_use_midi_work(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
25658c2ecf20Sopenharmony_ci{
25668c2ecf20Sopenharmony_ci	struct hdsp *hdsp = snd_kcontrol_chip(kcontrol);
25678c2ecf20Sopenharmony_ci
25688c2ecf20Sopenharmony_ci	spin_lock_irq(&hdsp->lock);
25698c2ecf20Sopenharmony_ci	ucontrol->value.integer.value[0] = hdsp->use_midi_work;
25708c2ecf20Sopenharmony_ci	spin_unlock_irq(&hdsp->lock);
25718c2ecf20Sopenharmony_ci	return 0;
25728c2ecf20Sopenharmony_ci}
25738c2ecf20Sopenharmony_ci
25748c2ecf20Sopenharmony_cistatic int snd_hdsp_put_use_midi_work(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
25758c2ecf20Sopenharmony_ci{
25768c2ecf20Sopenharmony_ci	struct hdsp *hdsp = snd_kcontrol_chip(kcontrol);
25778c2ecf20Sopenharmony_ci	int change;
25788c2ecf20Sopenharmony_ci	unsigned int val;
25798c2ecf20Sopenharmony_ci
25808c2ecf20Sopenharmony_ci	if (!snd_hdsp_use_is_exclusive(hdsp))
25818c2ecf20Sopenharmony_ci		return -EBUSY;
25828c2ecf20Sopenharmony_ci	val = ucontrol->value.integer.value[0] & 1;
25838c2ecf20Sopenharmony_ci	spin_lock_irq(&hdsp->lock);
25848c2ecf20Sopenharmony_ci	change = (int)val != hdsp->use_midi_work;
25858c2ecf20Sopenharmony_ci	hdsp_set_use_midi_work(hdsp, val);
25868c2ecf20Sopenharmony_ci	spin_unlock_irq(&hdsp->lock);
25878c2ecf20Sopenharmony_ci	return change;
25888c2ecf20Sopenharmony_ci}
25898c2ecf20Sopenharmony_ci
25908c2ecf20Sopenharmony_ci#define HDSP_MIXER(xname, xindex) \
25918c2ecf20Sopenharmony_ci{ .iface = SNDRV_CTL_ELEM_IFACE_HWDEP, \
25928c2ecf20Sopenharmony_ci  .name = xname, \
25938c2ecf20Sopenharmony_ci  .index = xindex, \
25948c2ecf20Sopenharmony_ci  .device = 0, \
25958c2ecf20Sopenharmony_ci  .access = SNDRV_CTL_ELEM_ACCESS_READWRITE | \
25968c2ecf20Sopenharmony_ci		 SNDRV_CTL_ELEM_ACCESS_VOLATILE, \
25978c2ecf20Sopenharmony_ci  .info = snd_hdsp_info_mixer, \
25988c2ecf20Sopenharmony_ci  .get = snd_hdsp_get_mixer, \
25998c2ecf20Sopenharmony_ci  .put = snd_hdsp_put_mixer \
26008c2ecf20Sopenharmony_ci}
26018c2ecf20Sopenharmony_ci
26028c2ecf20Sopenharmony_cistatic int snd_hdsp_info_mixer(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
26038c2ecf20Sopenharmony_ci{
26048c2ecf20Sopenharmony_ci	uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
26058c2ecf20Sopenharmony_ci	uinfo->count = 3;
26068c2ecf20Sopenharmony_ci	uinfo->value.integer.min = 0;
26078c2ecf20Sopenharmony_ci	uinfo->value.integer.max = 65536;
26088c2ecf20Sopenharmony_ci	uinfo->value.integer.step = 1;
26098c2ecf20Sopenharmony_ci	return 0;
26108c2ecf20Sopenharmony_ci}
26118c2ecf20Sopenharmony_ci
26128c2ecf20Sopenharmony_cistatic int snd_hdsp_get_mixer(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
26138c2ecf20Sopenharmony_ci{
26148c2ecf20Sopenharmony_ci	struct hdsp *hdsp = snd_kcontrol_chip(kcontrol);
26158c2ecf20Sopenharmony_ci	int source;
26168c2ecf20Sopenharmony_ci	int destination;
26178c2ecf20Sopenharmony_ci	int addr;
26188c2ecf20Sopenharmony_ci
26198c2ecf20Sopenharmony_ci	source = ucontrol->value.integer.value[0];
26208c2ecf20Sopenharmony_ci	destination = ucontrol->value.integer.value[1];
26218c2ecf20Sopenharmony_ci
26228c2ecf20Sopenharmony_ci	if (source >= hdsp->max_channels)
26238c2ecf20Sopenharmony_ci		addr = hdsp_playback_to_output_key(hdsp,source-hdsp->max_channels,destination);
26248c2ecf20Sopenharmony_ci	else
26258c2ecf20Sopenharmony_ci		addr = hdsp_input_to_output_key(hdsp,source, destination);
26268c2ecf20Sopenharmony_ci
26278c2ecf20Sopenharmony_ci	spin_lock_irq(&hdsp->lock);
26288c2ecf20Sopenharmony_ci	ucontrol->value.integer.value[2] = hdsp_read_gain (hdsp, addr);
26298c2ecf20Sopenharmony_ci	spin_unlock_irq(&hdsp->lock);
26308c2ecf20Sopenharmony_ci	return 0;
26318c2ecf20Sopenharmony_ci}
26328c2ecf20Sopenharmony_ci
26338c2ecf20Sopenharmony_cistatic int snd_hdsp_put_mixer(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
26348c2ecf20Sopenharmony_ci{
26358c2ecf20Sopenharmony_ci	struct hdsp *hdsp = snd_kcontrol_chip(kcontrol);
26368c2ecf20Sopenharmony_ci	int change;
26378c2ecf20Sopenharmony_ci	int source;
26388c2ecf20Sopenharmony_ci	int destination;
26398c2ecf20Sopenharmony_ci	int gain;
26408c2ecf20Sopenharmony_ci	int addr;
26418c2ecf20Sopenharmony_ci
26428c2ecf20Sopenharmony_ci	if (!snd_hdsp_use_is_exclusive(hdsp))
26438c2ecf20Sopenharmony_ci		return -EBUSY;
26448c2ecf20Sopenharmony_ci
26458c2ecf20Sopenharmony_ci	source = ucontrol->value.integer.value[0];
26468c2ecf20Sopenharmony_ci	destination = ucontrol->value.integer.value[1];
26478c2ecf20Sopenharmony_ci
26488c2ecf20Sopenharmony_ci	if (source >= hdsp->max_channels)
26498c2ecf20Sopenharmony_ci		addr = hdsp_playback_to_output_key(hdsp,source-hdsp->max_channels, destination);
26508c2ecf20Sopenharmony_ci	else
26518c2ecf20Sopenharmony_ci		addr = hdsp_input_to_output_key(hdsp,source, destination);
26528c2ecf20Sopenharmony_ci
26538c2ecf20Sopenharmony_ci	gain = ucontrol->value.integer.value[2];
26548c2ecf20Sopenharmony_ci
26558c2ecf20Sopenharmony_ci	spin_lock_irq(&hdsp->lock);
26568c2ecf20Sopenharmony_ci	change = gain != hdsp_read_gain(hdsp, addr);
26578c2ecf20Sopenharmony_ci	if (change)
26588c2ecf20Sopenharmony_ci		hdsp_write_gain(hdsp, addr, gain);
26598c2ecf20Sopenharmony_ci	spin_unlock_irq(&hdsp->lock);
26608c2ecf20Sopenharmony_ci	return change;
26618c2ecf20Sopenharmony_ci}
26628c2ecf20Sopenharmony_ci
26638c2ecf20Sopenharmony_ci#define HDSP_WC_SYNC_CHECK(xname, xindex) \
26648c2ecf20Sopenharmony_ci{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
26658c2ecf20Sopenharmony_ci  .name = xname, \
26668c2ecf20Sopenharmony_ci  .index = xindex, \
26678c2ecf20Sopenharmony_ci  .access = SNDRV_CTL_ELEM_ACCESS_READ | SNDRV_CTL_ELEM_ACCESS_VOLATILE, \
26688c2ecf20Sopenharmony_ci  .info = snd_hdsp_info_sync_check, \
26698c2ecf20Sopenharmony_ci  .get = snd_hdsp_get_wc_sync_check \
26708c2ecf20Sopenharmony_ci}
26718c2ecf20Sopenharmony_ci
26728c2ecf20Sopenharmony_cistatic int snd_hdsp_info_sync_check(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
26738c2ecf20Sopenharmony_ci{
26748c2ecf20Sopenharmony_ci	static const char * const texts[] = {"No Lock", "Lock", "Sync" };
26758c2ecf20Sopenharmony_ci
26768c2ecf20Sopenharmony_ci	return snd_ctl_enum_info(uinfo, 1, 3, texts);
26778c2ecf20Sopenharmony_ci}
26788c2ecf20Sopenharmony_ci
26798c2ecf20Sopenharmony_cistatic int hdsp_wc_sync_check(struct hdsp *hdsp)
26808c2ecf20Sopenharmony_ci{
26818c2ecf20Sopenharmony_ci	int status2 = hdsp_read(hdsp, HDSP_status2Register);
26828c2ecf20Sopenharmony_ci	if (status2 & HDSP_wc_lock) {
26838c2ecf20Sopenharmony_ci		if (status2 & HDSP_wc_sync)
26848c2ecf20Sopenharmony_ci			return 2;
26858c2ecf20Sopenharmony_ci		else
26868c2ecf20Sopenharmony_ci			 return 1;
26878c2ecf20Sopenharmony_ci	} else
26888c2ecf20Sopenharmony_ci		return 0;
26898c2ecf20Sopenharmony_ci	return 0;
26908c2ecf20Sopenharmony_ci}
26918c2ecf20Sopenharmony_ci
26928c2ecf20Sopenharmony_cistatic int snd_hdsp_get_wc_sync_check(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
26938c2ecf20Sopenharmony_ci{
26948c2ecf20Sopenharmony_ci	struct hdsp *hdsp = snd_kcontrol_chip(kcontrol);
26958c2ecf20Sopenharmony_ci
26968c2ecf20Sopenharmony_ci	ucontrol->value.enumerated.item[0] = hdsp_wc_sync_check(hdsp);
26978c2ecf20Sopenharmony_ci	return 0;
26988c2ecf20Sopenharmony_ci}
26998c2ecf20Sopenharmony_ci
27008c2ecf20Sopenharmony_ci#define HDSP_SPDIF_SYNC_CHECK(xname, xindex) \
27018c2ecf20Sopenharmony_ci{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
27028c2ecf20Sopenharmony_ci  .name = xname, \
27038c2ecf20Sopenharmony_ci  .index = xindex, \
27048c2ecf20Sopenharmony_ci  .access = SNDRV_CTL_ELEM_ACCESS_READ | SNDRV_CTL_ELEM_ACCESS_VOLATILE, \
27058c2ecf20Sopenharmony_ci  .info = snd_hdsp_info_sync_check, \
27068c2ecf20Sopenharmony_ci  .get = snd_hdsp_get_spdif_sync_check \
27078c2ecf20Sopenharmony_ci}
27088c2ecf20Sopenharmony_ci
27098c2ecf20Sopenharmony_cistatic int hdsp_spdif_sync_check(struct hdsp *hdsp)
27108c2ecf20Sopenharmony_ci{
27118c2ecf20Sopenharmony_ci	int status = hdsp_read(hdsp, HDSP_statusRegister);
27128c2ecf20Sopenharmony_ci	if (status & HDSP_SPDIFErrorFlag)
27138c2ecf20Sopenharmony_ci		return 0;
27148c2ecf20Sopenharmony_ci	else {
27158c2ecf20Sopenharmony_ci		if (status & HDSP_SPDIFSync)
27168c2ecf20Sopenharmony_ci			return 2;
27178c2ecf20Sopenharmony_ci		else
27188c2ecf20Sopenharmony_ci			return 1;
27198c2ecf20Sopenharmony_ci	}
27208c2ecf20Sopenharmony_ci	return 0;
27218c2ecf20Sopenharmony_ci}
27228c2ecf20Sopenharmony_ci
27238c2ecf20Sopenharmony_cistatic int snd_hdsp_get_spdif_sync_check(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
27248c2ecf20Sopenharmony_ci{
27258c2ecf20Sopenharmony_ci	struct hdsp *hdsp = snd_kcontrol_chip(kcontrol);
27268c2ecf20Sopenharmony_ci
27278c2ecf20Sopenharmony_ci	ucontrol->value.enumerated.item[0] = hdsp_spdif_sync_check(hdsp);
27288c2ecf20Sopenharmony_ci	return 0;
27298c2ecf20Sopenharmony_ci}
27308c2ecf20Sopenharmony_ci
27318c2ecf20Sopenharmony_ci#define HDSP_ADATSYNC_SYNC_CHECK(xname, xindex) \
27328c2ecf20Sopenharmony_ci{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
27338c2ecf20Sopenharmony_ci  .name = xname, \
27348c2ecf20Sopenharmony_ci  .index = xindex, \
27358c2ecf20Sopenharmony_ci  .access = SNDRV_CTL_ELEM_ACCESS_READ | SNDRV_CTL_ELEM_ACCESS_VOLATILE, \
27368c2ecf20Sopenharmony_ci  .info = snd_hdsp_info_sync_check, \
27378c2ecf20Sopenharmony_ci  .get = snd_hdsp_get_adatsync_sync_check \
27388c2ecf20Sopenharmony_ci}
27398c2ecf20Sopenharmony_ci
27408c2ecf20Sopenharmony_cistatic int hdsp_adatsync_sync_check(struct hdsp *hdsp)
27418c2ecf20Sopenharmony_ci{
27428c2ecf20Sopenharmony_ci	int status = hdsp_read(hdsp, HDSP_statusRegister);
27438c2ecf20Sopenharmony_ci	if (status & HDSP_TimecodeLock) {
27448c2ecf20Sopenharmony_ci		if (status & HDSP_TimecodeSync)
27458c2ecf20Sopenharmony_ci			return 2;
27468c2ecf20Sopenharmony_ci		else
27478c2ecf20Sopenharmony_ci			return 1;
27488c2ecf20Sopenharmony_ci	} else
27498c2ecf20Sopenharmony_ci		return 0;
27508c2ecf20Sopenharmony_ci}
27518c2ecf20Sopenharmony_ci
27528c2ecf20Sopenharmony_cistatic int snd_hdsp_get_adatsync_sync_check(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
27538c2ecf20Sopenharmony_ci{
27548c2ecf20Sopenharmony_ci	struct hdsp *hdsp = snd_kcontrol_chip(kcontrol);
27558c2ecf20Sopenharmony_ci
27568c2ecf20Sopenharmony_ci	ucontrol->value.enumerated.item[0] = hdsp_adatsync_sync_check(hdsp);
27578c2ecf20Sopenharmony_ci	return 0;
27588c2ecf20Sopenharmony_ci}
27598c2ecf20Sopenharmony_ci
27608c2ecf20Sopenharmony_ci#define HDSP_ADAT_SYNC_CHECK \
27618c2ecf20Sopenharmony_ci{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
27628c2ecf20Sopenharmony_ci  .access = SNDRV_CTL_ELEM_ACCESS_READ | SNDRV_CTL_ELEM_ACCESS_VOLATILE, \
27638c2ecf20Sopenharmony_ci  .info = snd_hdsp_info_sync_check, \
27648c2ecf20Sopenharmony_ci  .get = snd_hdsp_get_adat_sync_check \
27658c2ecf20Sopenharmony_ci}
27668c2ecf20Sopenharmony_ci
27678c2ecf20Sopenharmony_cistatic int hdsp_adat_sync_check(struct hdsp *hdsp, int idx)
27688c2ecf20Sopenharmony_ci{
27698c2ecf20Sopenharmony_ci	int status = hdsp_read(hdsp, HDSP_statusRegister);
27708c2ecf20Sopenharmony_ci
27718c2ecf20Sopenharmony_ci	if (status & (HDSP_Lock0>>idx)) {
27728c2ecf20Sopenharmony_ci		if (status & (HDSP_Sync0>>idx))
27738c2ecf20Sopenharmony_ci			return 2;
27748c2ecf20Sopenharmony_ci		else
27758c2ecf20Sopenharmony_ci			return 1;
27768c2ecf20Sopenharmony_ci	} else
27778c2ecf20Sopenharmony_ci		return 0;
27788c2ecf20Sopenharmony_ci}
27798c2ecf20Sopenharmony_ci
27808c2ecf20Sopenharmony_cistatic int snd_hdsp_get_adat_sync_check(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
27818c2ecf20Sopenharmony_ci{
27828c2ecf20Sopenharmony_ci	int offset;
27838c2ecf20Sopenharmony_ci	struct hdsp *hdsp = snd_kcontrol_chip(kcontrol);
27848c2ecf20Sopenharmony_ci
27858c2ecf20Sopenharmony_ci	offset = ucontrol->id.index - 1;
27868c2ecf20Sopenharmony_ci	if (snd_BUG_ON(offset < 0))
27878c2ecf20Sopenharmony_ci		return -EINVAL;
27888c2ecf20Sopenharmony_ci
27898c2ecf20Sopenharmony_ci	switch (hdsp->io_type) {
27908c2ecf20Sopenharmony_ci	case Digiface:
27918c2ecf20Sopenharmony_ci	case H9652:
27928c2ecf20Sopenharmony_ci		if (offset >= 3)
27938c2ecf20Sopenharmony_ci			return -EINVAL;
27948c2ecf20Sopenharmony_ci		break;
27958c2ecf20Sopenharmony_ci	case Multiface:
27968c2ecf20Sopenharmony_ci	case H9632:
27978c2ecf20Sopenharmony_ci		if (offset >= 1)
27988c2ecf20Sopenharmony_ci			return -EINVAL;
27998c2ecf20Sopenharmony_ci		break;
28008c2ecf20Sopenharmony_ci	default:
28018c2ecf20Sopenharmony_ci		return -EIO;
28028c2ecf20Sopenharmony_ci	}
28038c2ecf20Sopenharmony_ci
28048c2ecf20Sopenharmony_ci	ucontrol->value.enumerated.item[0] = hdsp_adat_sync_check(hdsp, offset);
28058c2ecf20Sopenharmony_ci	return 0;
28068c2ecf20Sopenharmony_ci}
28078c2ecf20Sopenharmony_ci
28088c2ecf20Sopenharmony_ci#define HDSP_DDS_OFFSET(xname, xindex) \
28098c2ecf20Sopenharmony_ci{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
28108c2ecf20Sopenharmony_ci  .name = xname, \
28118c2ecf20Sopenharmony_ci  .index = xindex, \
28128c2ecf20Sopenharmony_ci  .info = snd_hdsp_info_dds_offset, \
28138c2ecf20Sopenharmony_ci  .get = snd_hdsp_get_dds_offset, \
28148c2ecf20Sopenharmony_ci  .put = snd_hdsp_put_dds_offset \
28158c2ecf20Sopenharmony_ci}
28168c2ecf20Sopenharmony_ci
28178c2ecf20Sopenharmony_cistatic int hdsp_dds_offset(struct hdsp *hdsp)
28188c2ecf20Sopenharmony_ci{
28198c2ecf20Sopenharmony_ci	u64 n;
28208c2ecf20Sopenharmony_ci	unsigned int dds_value = hdsp->dds_value;
28218c2ecf20Sopenharmony_ci	int system_sample_rate = hdsp->system_sample_rate;
28228c2ecf20Sopenharmony_ci
28238c2ecf20Sopenharmony_ci	if (!dds_value)
28248c2ecf20Sopenharmony_ci		return 0;
28258c2ecf20Sopenharmony_ci
28268c2ecf20Sopenharmony_ci	n = DDS_NUMERATOR;
28278c2ecf20Sopenharmony_ci	/*
28288c2ecf20Sopenharmony_ci	 * dds_value = n / rate
28298c2ecf20Sopenharmony_ci	 * rate = n / dds_value
28308c2ecf20Sopenharmony_ci	 */
28318c2ecf20Sopenharmony_ci	n = div_u64(n, dds_value);
28328c2ecf20Sopenharmony_ci	if (system_sample_rate >= 112000)
28338c2ecf20Sopenharmony_ci		n *= 4;
28348c2ecf20Sopenharmony_ci	else if (system_sample_rate >= 56000)
28358c2ecf20Sopenharmony_ci		n *= 2;
28368c2ecf20Sopenharmony_ci	return ((int)n) - system_sample_rate;
28378c2ecf20Sopenharmony_ci}
28388c2ecf20Sopenharmony_ci
28398c2ecf20Sopenharmony_cistatic int hdsp_set_dds_offset(struct hdsp *hdsp, int offset_hz)
28408c2ecf20Sopenharmony_ci{
28418c2ecf20Sopenharmony_ci	int rate = hdsp->system_sample_rate + offset_hz;
28428c2ecf20Sopenharmony_ci	hdsp_set_dds_value(hdsp, rate);
28438c2ecf20Sopenharmony_ci	return 0;
28448c2ecf20Sopenharmony_ci}
28458c2ecf20Sopenharmony_ci
28468c2ecf20Sopenharmony_cistatic int snd_hdsp_info_dds_offset(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
28478c2ecf20Sopenharmony_ci{
28488c2ecf20Sopenharmony_ci	uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
28498c2ecf20Sopenharmony_ci	uinfo->count = 1;
28508c2ecf20Sopenharmony_ci	uinfo->value.integer.min = -5000;
28518c2ecf20Sopenharmony_ci	uinfo->value.integer.max = 5000;
28528c2ecf20Sopenharmony_ci	return 0;
28538c2ecf20Sopenharmony_ci}
28548c2ecf20Sopenharmony_ci
28558c2ecf20Sopenharmony_cistatic int snd_hdsp_get_dds_offset(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
28568c2ecf20Sopenharmony_ci{
28578c2ecf20Sopenharmony_ci	struct hdsp *hdsp = snd_kcontrol_chip(kcontrol);
28588c2ecf20Sopenharmony_ci
28598c2ecf20Sopenharmony_ci	ucontrol->value.integer.value[0] = hdsp_dds_offset(hdsp);
28608c2ecf20Sopenharmony_ci	return 0;
28618c2ecf20Sopenharmony_ci}
28628c2ecf20Sopenharmony_ci
28638c2ecf20Sopenharmony_cistatic int snd_hdsp_put_dds_offset(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
28648c2ecf20Sopenharmony_ci{
28658c2ecf20Sopenharmony_ci	struct hdsp *hdsp = snd_kcontrol_chip(kcontrol);
28668c2ecf20Sopenharmony_ci	int change;
28678c2ecf20Sopenharmony_ci	int val;
28688c2ecf20Sopenharmony_ci
28698c2ecf20Sopenharmony_ci	if (!snd_hdsp_use_is_exclusive(hdsp))
28708c2ecf20Sopenharmony_ci		return -EBUSY;
28718c2ecf20Sopenharmony_ci	val = ucontrol->value.integer.value[0];
28728c2ecf20Sopenharmony_ci	spin_lock_irq(&hdsp->lock);
28738c2ecf20Sopenharmony_ci	if (val != hdsp_dds_offset(hdsp))
28748c2ecf20Sopenharmony_ci		change = (hdsp_set_dds_offset(hdsp, val) == 0) ? 1 : 0;
28758c2ecf20Sopenharmony_ci	else
28768c2ecf20Sopenharmony_ci		change = 0;
28778c2ecf20Sopenharmony_ci	spin_unlock_irq(&hdsp->lock);
28788c2ecf20Sopenharmony_ci	return change;
28798c2ecf20Sopenharmony_ci}
28808c2ecf20Sopenharmony_ci
28818c2ecf20Sopenharmony_cistatic const struct snd_kcontrol_new snd_hdsp_9632_controls[] = {
28828c2ecf20Sopenharmony_ciHDSP_DA_GAIN("DA Gain", 0),
28838c2ecf20Sopenharmony_ciHDSP_AD_GAIN("AD Gain", 0),
28848c2ecf20Sopenharmony_ciHDSP_PHONE_GAIN("Phones Gain", 0),
28858c2ecf20Sopenharmony_ciHDSP_TOGGLE_SETTING("XLR Breakout Cable", HDSP_XLRBreakoutCable),
28868c2ecf20Sopenharmony_ciHDSP_DDS_OFFSET("DDS Sample Rate Offset", 0)
28878c2ecf20Sopenharmony_ci};
28888c2ecf20Sopenharmony_ci
28898c2ecf20Sopenharmony_cistatic const struct snd_kcontrol_new snd_hdsp_controls[] = {
28908c2ecf20Sopenharmony_ci{
28918c2ecf20Sopenharmony_ci	.iface =	SNDRV_CTL_ELEM_IFACE_PCM,
28928c2ecf20Sopenharmony_ci	.name =		SNDRV_CTL_NAME_IEC958("",PLAYBACK,DEFAULT),
28938c2ecf20Sopenharmony_ci	.info =		snd_hdsp_control_spdif_info,
28948c2ecf20Sopenharmony_ci	.get =		snd_hdsp_control_spdif_get,
28958c2ecf20Sopenharmony_ci	.put =		snd_hdsp_control_spdif_put,
28968c2ecf20Sopenharmony_ci},
28978c2ecf20Sopenharmony_ci{
28988c2ecf20Sopenharmony_ci	.access =	SNDRV_CTL_ELEM_ACCESS_READWRITE | SNDRV_CTL_ELEM_ACCESS_INACTIVE,
28998c2ecf20Sopenharmony_ci	.iface =	SNDRV_CTL_ELEM_IFACE_PCM,
29008c2ecf20Sopenharmony_ci	.name =		SNDRV_CTL_NAME_IEC958("",PLAYBACK,PCM_STREAM),
29018c2ecf20Sopenharmony_ci	.info =		snd_hdsp_control_spdif_stream_info,
29028c2ecf20Sopenharmony_ci	.get =		snd_hdsp_control_spdif_stream_get,
29038c2ecf20Sopenharmony_ci	.put =		snd_hdsp_control_spdif_stream_put,
29048c2ecf20Sopenharmony_ci},
29058c2ecf20Sopenharmony_ci{
29068c2ecf20Sopenharmony_ci	.access =	SNDRV_CTL_ELEM_ACCESS_READ,
29078c2ecf20Sopenharmony_ci	.iface =	SNDRV_CTL_ELEM_IFACE_PCM,
29088c2ecf20Sopenharmony_ci	.name =		SNDRV_CTL_NAME_IEC958("",PLAYBACK,CON_MASK),
29098c2ecf20Sopenharmony_ci	.info =		snd_hdsp_control_spdif_mask_info,
29108c2ecf20Sopenharmony_ci	.get =		snd_hdsp_control_spdif_mask_get,
29118c2ecf20Sopenharmony_ci	.private_value = IEC958_AES0_NONAUDIO |
29128c2ecf20Sopenharmony_ci  			 IEC958_AES0_PROFESSIONAL |
29138c2ecf20Sopenharmony_ci			 IEC958_AES0_CON_EMPHASIS,
29148c2ecf20Sopenharmony_ci},
29158c2ecf20Sopenharmony_ci{
29168c2ecf20Sopenharmony_ci	.access =	SNDRV_CTL_ELEM_ACCESS_READ,
29178c2ecf20Sopenharmony_ci	.iface =	SNDRV_CTL_ELEM_IFACE_PCM,
29188c2ecf20Sopenharmony_ci	.name =		SNDRV_CTL_NAME_IEC958("",PLAYBACK,PRO_MASK),
29198c2ecf20Sopenharmony_ci	.info =		snd_hdsp_control_spdif_mask_info,
29208c2ecf20Sopenharmony_ci	.get =		snd_hdsp_control_spdif_mask_get,
29218c2ecf20Sopenharmony_ci	.private_value = IEC958_AES0_NONAUDIO |
29228c2ecf20Sopenharmony_ci			 IEC958_AES0_PROFESSIONAL |
29238c2ecf20Sopenharmony_ci			 IEC958_AES0_PRO_EMPHASIS,
29248c2ecf20Sopenharmony_ci},
29258c2ecf20Sopenharmony_ciHDSP_MIXER("Mixer", 0),
29268c2ecf20Sopenharmony_ciHDSP_SPDIF_IN("IEC958 Input Connector", 0),
29278c2ecf20Sopenharmony_ciHDSP_TOGGLE_SETTING("IEC958 Output also on ADAT1", HDSP_SPDIFOpticalOut),
29288c2ecf20Sopenharmony_ciHDSP_TOGGLE_SETTING("IEC958 Professional Bit", HDSP_SPDIFProfessional),
29298c2ecf20Sopenharmony_ciHDSP_TOGGLE_SETTING("IEC958 Emphasis Bit", HDSP_SPDIFEmphasis),
29308c2ecf20Sopenharmony_ciHDSP_TOGGLE_SETTING("IEC958 Non-audio Bit", HDSP_SPDIFNonAudio),
29318c2ecf20Sopenharmony_ci/* 'Sample Clock Source' complies with the alsa control naming scheme */
29328c2ecf20Sopenharmony_ciHDSP_CLOCK_SOURCE("Sample Clock Source", 0),
29338c2ecf20Sopenharmony_ci{
29348c2ecf20Sopenharmony_ci	.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
29358c2ecf20Sopenharmony_ci	.name = "Sample Clock Source Locking",
29368c2ecf20Sopenharmony_ci	.info = snd_hdsp_info_clock_source_lock,
29378c2ecf20Sopenharmony_ci	.get = snd_hdsp_get_clock_source_lock,
29388c2ecf20Sopenharmony_ci	.put = snd_hdsp_put_clock_source_lock,
29398c2ecf20Sopenharmony_ci},
29408c2ecf20Sopenharmony_ciHDSP_SYSTEM_CLOCK_MODE("System Clock Mode", 0),
29418c2ecf20Sopenharmony_ciHDSP_PREF_SYNC_REF("Preferred Sync Reference", 0),
29428c2ecf20Sopenharmony_ciHDSP_AUTOSYNC_REF("AutoSync Reference", 0),
29438c2ecf20Sopenharmony_ciHDSP_SPDIF_SAMPLE_RATE("SPDIF Sample Rate", 0),
29448c2ecf20Sopenharmony_ciHDSP_SYSTEM_SAMPLE_RATE("System Sample Rate", 0),
29458c2ecf20Sopenharmony_ci/* 'External Rate' complies with the alsa control naming scheme */
29468c2ecf20Sopenharmony_ciHDSP_AUTOSYNC_SAMPLE_RATE("External Rate", 0),
29478c2ecf20Sopenharmony_ciHDSP_WC_SYNC_CHECK("Word Clock Lock Status", 0),
29488c2ecf20Sopenharmony_ciHDSP_SPDIF_SYNC_CHECK("SPDIF Lock Status", 0),
29498c2ecf20Sopenharmony_ciHDSP_ADATSYNC_SYNC_CHECK("ADAT Sync Lock Status", 0),
29508c2ecf20Sopenharmony_ciHDSP_TOGGLE_SETTING("Line Out", HDSP_LineOut),
29518c2ecf20Sopenharmony_ciHDSP_PRECISE_POINTER("Precise Pointer", 0),
29528c2ecf20Sopenharmony_ciHDSP_USE_MIDI_WORK("Use Midi Tasklet", 0),
29538c2ecf20Sopenharmony_ci};
29548c2ecf20Sopenharmony_ci
29558c2ecf20Sopenharmony_ci
29568c2ecf20Sopenharmony_cistatic int hdsp_rpm_input12(struct hdsp *hdsp)
29578c2ecf20Sopenharmony_ci{
29588c2ecf20Sopenharmony_ci	switch (hdsp->control_register & HDSP_RPM_Inp12) {
29598c2ecf20Sopenharmony_ci	case HDSP_RPM_Inp12_Phon_6dB:
29608c2ecf20Sopenharmony_ci		return 0;
29618c2ecf20Sopenharmony_ci	case HDSP_RPM_Inp12_Phon_n6dB:
29628c2ecf20Sopenharmony_ci		return 2;
29638c2ecf20Sopenharmony_ci	case HDSP_RPM_Inp12_Line_0dB:
29648c2ecf20Sopenharmony_ci		return 3;
29658c2ecf20Sopenharmony_ci	case HDSP_RPM_Inp12_Line_n6dB:
29668c2ecf20Sopenharmony_ci		return 4;
29678c2ecf20Sopenharmony_ci	}
29688c2ecf20Sopenharmony_ci	return 1;
29698c2ecf20Sopenharmony_ci}
29708c2ecf20Sopenharmony_ci
29718c2ecf20Sopenharmony_ci
29728c2ecf20Sopenharmony_cistatic int snd_hdsp_get_rpm_input12(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
29738c2ecf20Sopenharmony_ci{
29748c2ecf20Sopenharmony_ci	struct hdsp *hdsp = snd_kcontrol_chip(kcontrol);
29758c2ecf20Sopenharmony_ci
29768c2ecf20Sopenharmony_ci	ucontrol->value.enumerated.item[0] = hdsp_rpm_input12(hdsp);
29778c2ecf20Sopenharmony_ci	return 0;
29788c2ecf20Sopenharmony_ci}
29798c2ecf20Sopenharmony_ci
29808c2ecf20Sopenharmony_ci
29818c2ecf20Sopenharmony_cistatic int hdsp_set_rpm_input12(struct hdsp *hdsp, int mode)
29828c2ecf20Sopenharmony_ci{
29838c2ecf20Sopenharmony_ci	hdsp->control_register &= ~HDSP_RPM_Inp12;
29848c2ecf20Sopenharmony_ci	switch (mode) {
29858c2ecf20Sopenharmony_ci	case 0:
29868c2ecf20Sopenharmony_ci		hdsp->control_register |= HDSP_RPM_Inp12_Phon_6dB;
29878c2ecf20Sopenharmony_ci		break;
29888c2ecf20Sopenharmony_ci	case 1:
29898c2ecf20Sopenharmony_ci		break;
29908c2ecf20Sopenharmony_ci	case 2:
29918c2ecf20Sopenharmony_ci		hdsp->control_register |= HDSP_RPM_Inp12_Phon_n6dB;
29928c2ecf20Sopenharmony_ci		break;
29938c2ecf20Sopenharmony_ci	case 3:
29948c2ecf20Sopenharmony_ci		hdsp->control_register |= HDSP_RPM_Inp12_Line_0dB;
29958c2ecf20Sopenharmony_ci		break;
29968c2ecf20Sopenharmony_ci	case 4:
29978c2ecf20Sopenharmony_ci		hdsp->control_register |= HDSP_RPM_Inp12_Line_n6dB;
29988c2ecf20Sopenharmony_ci		break;
29998c2ecf20Sopenharmony_ci	default:
30008c2ecf20Sopenharmony_ci		return -1;
30018c2ecf20Sopenharmony_ci	}
30028c2ecf20Sopenharmony_ci
30038c2ecf20Sopenharmony_ci	hdsp_write(hdsp, HDSP_controlRegister, hdsp->control_register);
30048c2ecf20Sopenharmony_ci	return 0;
30058c2ecf20Sopenharmony_ci}
30068c2ecf20Sopenharmony_ci
30078c2ecf20Sopenharmony_ci
30088c2ecf20Sopenharmony_cistatic int snd_hdsp_put_rpm_input12(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
30098c2ecf20Sopenharmony_ci{
30108c2ecf20Sopenharmony_ci	struct hdsp *hdsp = snd_kcontrol_chip(kcontrol);
30118c2ecf20Sopenharmony_ci	int change;
30128c2ecf20Sopenharmony_ci	int val;
30138c2ecf20Sopenharmony_ci
30148c2ecf20Sopenharmony_ci	if (!snd_hdsp_use_is_exclusive(hdsp))
30158c2ecf20Sopenharmony_ci		return -EBUSY;
30168c2ecf20Sopenharmony_ci	val = ucontrol->value.enumerated.item[0];
30178c2ecf20Sopenharmony_ci	if (val < 0)
30188c2ecf20Sopenharmony_ci		val = 0;
30198c2ecf20Sopenharmony_ci	if (val > 4)
30208c2ecf20Sopenharmony_ci		val = 4;
30218c2ecf20Sopenharmony_ci	spin_lock_irq(&hdsp->lock);
30228c2ecf20Sopenharmony_ci	if (val != hdsp_rpm_input12(hdsp))
30238c2ecf20Sopenharmony_ci		change = (hdsp_set_rpm_input12(hdsp, val) == 0) ? 1 : 0;
30248c2ecf20Sopenharmony_ci	else
30258c2ecf20Sopenharmony_ci		change = 0;
30268c2ecf20Sopenharmony_ci	spin_unlock_irq(&hdsp->lock);
30278c2ecf20Sopenharmony_ci	return change;
30288c2ecf20Sopenharmony_ci}
30298c2ecf20Sopenharmony_ci
30308c2ecf20Sopenharmony_ci
30318c2ecf20Sopenharmony_cistatic int snd_hdsp_info_rpm_input(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
30328c2ecf20Sopenharmony_ci{
30338c2ecf20Sopenharmony_ci	static const char * const texts[] = {
30348c2ecf20Sopenharmony_ci		"Phono +6dB", "Phono 0dB", "Phono -6dB", "Line 0dB", "Line -6dB"
30358c2ecf20Sopenharmony_ci	};
30368c2ecf20Sopenharmony_ci
30378c2ecf20Sopenharmony_ci	return snd_ctl_enum_info(uinfo, 1, 5, texts);
30388c2ecf20Sopenharmony_ci}
30398c2ecf20Sopenharmony_ci
30408c2ecf20Sopenharmony_ci
30418c2ecf20Sopenharmony_cistatic int hdsp_rpm_input34(struct hdsp *hdsp)
30428c2ecf20Sopenharmony_ci{
30438c2ecf20Sopenharmony_ci	switch (hdsp->control_register & HDSP_RPM_Inp34) {
30448c2ecf20Sopenharmony_ci	case HDSP_RPM_Inp34_Phon_6dB:
30458c2ecf20Sopenharmony_ci		return 0;
30468c2ecf20Sopenharmony_ci	case HDSP_RPM_Inp34_Phon_n6dB:
30478c2ecf20Sopenharmony_ci		return 2;
30488c2ecf20Sopenharmony_ci	case HDSP_RPM_Inp34_Line_0dB:
30498c2ecf20Sopenharmony_ci		return 3;
30508c2ecf20Sopenharmony_ci	case HDSP_RPM_Inp34_Line_n6dB:
30518c2ecf20Sopenharmony_ci		return 4;
30528c2ecf20Sopenharmony_ci	}
30538c2ecf20Sopenharmony_ci	return 1;
30548c2ecf20Sopenharmony_ci}
30558c2ecf20Sopenharmony_ci
30568c2ecf20Sopenharmony_ci
30578c2ecf20Sopenharmony_cistatic int snd_hdsp_get_rpm_input34(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
30588c2ecf20Sopenharmony_ci{
30598c2ecf20Sopenharmony_ci	struct hdsp *hdsp = snd_kcontrol_chip(kcontrol);
30608c2ecf20Sopenharmony_ci
30618c2ecf20Sopenharmony_ci	ucontrol->value.enumerated.item[0] = hdsp_rpm_input34(hdsp);
30628c2ecf20Sopenharmony_ci	return 0;
30638c2ecf20Sopenharmony_ci}
30648c2ecf20Sopenharmony_ci
30658c2ecf20Sopenharmony_ci
30668c2ecf20Sopenharmony_cistatic int hdsp_set_rpm_input34(struct hdsp *hdsp, int mode)
30678c2ecf20Sopenharmony_ci{
30688c2ecf20Sopenharmony_ci	hdsp->control_register &= ~HDSP_RPM_Inp34;
30698c2ecf20Sopenharmony_ci	switch (mode) {
30708c2ecf20Sopenharmony_ci	case 0:
30718c2ecf20Sopenharmony_ci		hdsp->control_register |= HDSP_RPM_Inp34_Phon_6dB;
30728c2ecf20Sopenharmony_ci		break;
30738c2ecf20Sopenharmony_ci	case 1:
30748c2ecf20Sopenharmony_ci		break;
30758c2ecf20Sopenharmony_ci	case 2:
30768c2ecf20Sopenharmony_ci		hdsp->control_register |= HDSP_RPM_Inp34_Phon_n6dB;
30778c2ecf20Sopenharmony_ci		break;
30788c2ecf20Sopenharmony_ci	case 3:
30798c2ecf20Sopenharmony_ci		hdsp->control_register |= HDSP_RPM_Inp34_Line_0dB;
30808c2ecf20Sopenharmony_ci		break;
30818c2ecf20Sopenharmony_ci	case 4:
30828c2ecf20Sopenharmony_ci		hdsp->control_register |= HDSP_RPM_Inp34_Line_n6dB;
30838c2ecf20Sopenharmony_ci		break;
30848c2ecf20Sopenharmony_ci	default:
30858c2ecf20Sopenharmony_ci		return -1;
30868c2ecf20Sopenharmony_ci	}
30878c2ecf20Sopenharmony_ci
30888c2ecf20Sopenharmony_ci	hdsp_write(hdsp, HDSP_controlRegister, hdsp->control_register);
30898c2ecf20Sopenharmony_ci	return 0;
30908c2ecf20Sopenharmony_ci}
30918c2ecf20Sopenharmony_ci
30928c2ecf20Sopenharmony_ci
30938c2ecf20Sopenharmony_cistatic int snd_hdsp_put_rpm_input34(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
30948c2ecf20Sopenharmony_ci{
30958c2ecf20Sopenharmony_ci	struct hdsp *hdsp = snd_kcontrol_chip(kcontrol);
30968c2ecf20Sopenharmony_ci	int change;
30978c2ecf20Sopenharmony_ci	int val;
30988c2ecf20Sopenharmony_ci
30998c2ecf20Sopenharmony_ci	if (!snd_hdsp_use_is_exclusive(hdsp))
31008c2ecf20Sopenharmony_ci		return -EBUSY;
31018c2ecf20Sopenharmony_ci	val = ucontrol->value.enumerated.item[0];
31028c2ecf20Sopenharmony_ci	if (val < 0)
31038c2ecf20Sopenharmony_ci		val = 0;
31048c2ecf20Sopenharmony_ci	if (val > 4)
31058c2ecf20Sopenharmony_ci		val = 4;
31068c2ecf20Sopenharmony_ci	spin_lock_irq(&hdsp->lock);
31078c2ecf20Sopenharmony_ci	if (val != hdsp_rpm_input34(hdsp))
31088c2ecf20Sopenharmony_ci		change = (hdsp_set_rpm_input34(hdsp, val) == 0) ? 1 : 0;
31098c2ecf20Sopenharmony_ci	else
31108c2ecf20Sopenharmony_ci		change = 0;
31118c2ecf20Sopenharmony_ci	spin_unlock_irq(&hdsp->lock);
31128c2ecf20Sopenharmony_ci	return change;
31138c2ecf20Sopenharmony_ci}
31148c2ecf20Sopenharmony_ci
31158c2ecf20Sopenharmony_ci
31168c2ecf20Sopenharmony_ci/* RPM Bypass switch */
31178c2ecf20Sopenharmony_cistatic int hdsp_rpm_bypass(struct hdsp *hdsp)
31188c2ecf20Sopenharmony_ci{
31198c2ecf20Sopenharmony_ci	return (hdsp->control_register & HDSP_RPM_Bypass) ? 1 : 0;
31208c2ecf20Sopenharmony_ci}
31218c2ecf20Sopenharmony_ci
31228c2ecf20Sopenharmony_ci
31238c2ecf20Sopenharmony_cistatic int snd_hdsp_get_rpm_bypass(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
31248c2ecf20Sopenharmony_ci{
31258c2ecf20Sopenharmony_ci	struct hdsp *hdsp = snd_kcontrol_chip(kcontrol);
31268c2ecf20Sopenharmony_ci
31278c2ecf20Sopenharmony_ci	ucontrol->value.integer.value[0] = hdsp_rpm_bypass(hdsp);
31288c2ecf20Sopenharmony_ci	return 0;
31298c2ecf20Sopenharmony_ci}
31308c2ecf20Sopenharmony_ci
31318c2ecf20Sopenharmony_ci
31328c2ecf20Sopenharmony_cistatic int hdsp_set_rpm_bypass(struct hdsp *hdsp, int on)
31338c2ecf20Sopenharmony_ci{
31348c2ecf20Sopenharmony_ci	if (on)
31358c2ecf20Sopenharmony_ci		hdsp->control_register |= HDSP_RPM_Bypass;
31368c2ecf20Sopenharmony_ci	else
31378c2ecf20Sopenharmony_ci		hdsp->control_register &= ~HDSP_RPM_Bypass;
31388c2ecf20Sopenharmony_ci	hdsp_write(hdsp, HDSP_controlRegister, hdsp->control_register);
31398c2ecf20Sopenharmony_ci	return 0;
31408c2ecf20Sopenharmony_ci}
31418c2ecf20Sopenharmony_ci
31428c2ecf20Sopenharmony_ci
31438c2ecf20Sopenharmony_cistatic int snd_hdsp_put_rpm_bypass(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
31448c2ecf20Sopenharmony_ci{
31458c2ecf20Sopenharmony_ci	struct hdsp *hdsp = snd_kcontrol_chip(kcontrol);
31468c2ecf20Sopenharmony_ci	int change;
31478c2ecf20Sopenharmony_ci	unsigned int val;
31488c2ecf20Sopenharmony_ci
31498c2ecf20Sopenharmony_ci	if (!snd_hdsp_use_is_exclusive(hdsp))
31508c2ecf20Sopenharmony_ci		return -EBUSY;
31518c2ecf20Sopenharmony_ci	val = ucontrol->value.integer.value[0] & 1;
31528c2ecf20Sopenharmony_ci	spin_lock_irq(&hdsp->lock);
31538c2ecf20Sopenharmony_ci	change = (int)val != hdsp_rpm_bypass(hdsp);
31548c2ecf20Sopenharmony_ci	hdsp_set_rpm_bypass(hdsp, val);
31558c2ecf20Sopenharmony_ci	spin_unlock_irq(&hdsp->lock);
31568c2ecf20Sopenharmony_ci	return change;
31578c2ecf20Sopenharmony_ci}
31588c2ecf20Sopenharmony_ci
31598c2ecf20Sopenharmony_ci
31608c2ecf20Sopenharmony_cistatic int snd_hdsp_info_rpm_bypass(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
31618c2ecf20Sopenharmony_ci{
31628c2ecf20Sopenharmony_ci	static const char * const texts[] = {"On", "Off"};
31638c2ecf20Sopenharmony_ci
31648c2ecf20Sopenharmony_ci	return snd_ctl_enum_info(uinfo, 1, 2, texts);
31658c2ecf20Sopenharmony_ci}
31668c2ecf20Sopenharmony_ci
31678c2ecf20Sopenharmony_ci
31688c2ecf20Sopenharmony_ci/* RPM Disconnect switch */
31698c2ecf20Sopenharmony_cistatic int hdsp_rpm_disconnect(struct hdsp *hdsp)
31708c2ecf20Sopenharmony_ci{
31718c2ecf20Sopenharmony_ci	return (hdsp->control_register & HDSP_RPM_Disconnect) ? 1 : 0;
31728c2ecf20Sopenharmony_ci}
31738c2ecf20Sopenharmony_ci
31748c2ecf20Sopenharmony_ci
31758c2ecf20Sopenharmony_cistatic int snd_hdsp_get_rpm_disconnect(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
31768c2ecf20Sopenharmony_ci{
31778c2ecf20Sopenharmony_ci	struct hdsp *hdsp = snd_kcontrol_chip(kcontrol);
31788c2ecf20Sopenharmony_ci
31798c2ecf20Sopenharmony_ci	ucontrol->value.integer.value[0] = hdsp_rpm_disconnect(hdsp);
31808c2ecf20Sopenharmony_ci	return 0;
31818c2ecf20Sopenharmony_ci}
31828c2ecf20Sopenharmony_ci
31838c2ecf20Sopenharmony_ci
31848c2ecf20Sopenharmony_cistatic int hdsp_set_rpm_disconnect(struct hdsp *hdsp, int on)
31858c2ecf20Sopenharmony_ci{
31868c2ecf20Sopenharmony_ci	if (on)
31878c2ecf20Sopenharmony_ci		hdsp->control_register |= HDSP_RPM_Disconnect;
31888c2ecf20Sopenharmony_ci	else
31898c2ecf20Sopenharmony_ci		hdsp->control_register &= ~HDSP_RPM_Disconnect;
31908c2ecf20Sopenharmony_ci	hdsp_write(hdsp, HDSP_controlRegister, hdsp->control_register);
31918c2ecf20Sopenharmony_ci	return 0;
31928c2ecf20Sopenharmony_ci}
31938c2ecf20Sopenharmony_ci
31948c2ecf20Sopenharmony_ci
31958c2ecf20Sopenharmony_cistatic int snd_hdsp_put_rpm_disconnect(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
31968c2ecf20Sopenharmony_ci{
31978c2ecf20Sopenharmony_ci	struct hdsp *hdsp = snd_kcontrol_chip(kcontrol);
31988c2ecf20Sopenharmony_ci	int change;
31998c2ecf20Sopenharmony_ci	unsigned int val;
32008c2ecf20Sopenharmony_ci
32018c2ecf20Sopenharmony_ci	if (!snd_hdsp_use_is_exclusive(hdsp))
32028c2ecf20Sopenharmony_ci		return -EBUSY;
32038c2ecf20Sopenharmony_ci	val = ucontrol->value.integer.value[0] & 1;
32048c2ecf20Sopenharmony_ci	spin_lock_irq(&hdsp->lock);
32058c2ecf20Sopenharmony_ci	change = (int)val != hdsp_rpm_disconnect(hdsp);
32068c2ecf20Sopenharmony_ci	hdsp_set_rpm_disconnect(hdsp, val);
32078c2ecf20Sopenharmony_ci	spin_unlock_irq(&hdsp->lock);
32088c2ecf20Sopenharmony_ci	return change;
32098c2ecf20Sopenharmony_ci}
32108c2ecf20Sopenharmony_ci
32118c2ecf20Sopenharmony_cistatic int snd_hdsp_info_rpm_disconnect(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
32128c2ecf20Sopenharmony_ci{
32138c2ecf20Sopenharmony_ci	static const char * const texts[] = {"On", "Off"};
32148c2ecf20Sopenharmony_ci
32158c2ecf20Sopenharmony_ci	return snd_ctl_enum_info(uinfo, 1, 2, texts);
32168c2ecf20Sopenharmony_ci}
32178c2ecf20Sopenharmony_ci
32188c2ecf20Sopenharmony_cistatic const struct snd_kcontrol_new snd_hdsp_rpm_controls[] = {
32198c2ecf20Sopenharmony_ci	{
32208c2ecf20Sopenharmony_ci		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
32218c2ecf20Sopenharmony_ci		.name = "RPM Bypass",
32228c2ecf20Sopenharmony_ci		.get = snd_hdsp_get_rpm_bypass,
32238c2ecf20Sopenharmony_ci		.put = snd_hdsp_put_rpm_bypass,
32248c2ecf20Sopenharmony_ci		.info = snd_hdsp_info_rpm_bypass
32258c2ecf20Sopenharmony_ci	},
32268c2ecf20Sopenharmony_ci	{
32278c2ecf20Sopenharmony_ci		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
32288c2ecf20Sopenharmony_ci		.name = "RPM Disconnect",
32298c2ecf20Sopenharmony_ci		.get = snd_hdsp_get_rpm_disconnect,
32308c2ecf20Sopenharmony_ci		.put = snd_hdsp_put_rpm_disconnect,
32318c2ecf20Sopenharmony_ci		.info = snd_hdsp_info_rpm_disconnect
32328c2ecf20Sopenharmony_ci	},
32338c2ecf20Sopenharmony_ci	{
32348c2ecf20Sopenharmony_ci		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
32358c2ecf20Sopenharmony_ci		.name = "Input 1/2",
32368c2ecf20Sopenharmony_ci		.get = snd_hdsp_get_rpm_input12,
32378c2ecf20Sopenharmony_ci		.put = snd_hdsp_put_rpm_input12,
32388c2ecf20Sopenharmony_ci		.info = snd_hdsp_info_rpm_input
32398c2ecf20Sopenharmony_ci	},
32408c2ecf20Sopenharmony_ci	{
32418c2ecf20Sopenharmony_ci		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
32428c2ecf20Sopenharmony_ci		.name = "Input 3/4",
32438c2ecf20Sopenharmony_ci		.get = snd_hdsp_get_rpm_input34,
32448c2ecf20Sopenharmony_ci		.put = snd_hdsp_put_rpm_input34,
32458c2ecf20Sopenharmony_ci		.info = snd_hdsp_info_rpm_input
32468c2ecf20Sopenharmony_ci	},
32478c2ecf20Sopenharmony_ci	HDSP_SYSTEM_SAMPLE_RATE("System Sample Rate", 0),
32488c2ecf20Sopenharmony_ci	HDSP_MIXER("Mixer", 0)
32498c2ecf20Sopenharmony_ci};
32508c2ecf20Sopenharmony_ci
32518c2ecf20Sopenharmony_cistatic const struct snd_kcontrol_new snd_hdsp_96xx_aeb =
32528c2ecf20Sopenharmony_ci	HDSP_TOGGLE_SETTING("Analog Extension Board",
32538c2ecf20Sopenharmony_ci			HDSP_AnalogExtensionBoard);
32548c2ecf20Sopenharmony_cistatic struct snd_kcontrol_new snd_hdsp_adat_sync_check = HDSP_ADAT_SYNC_CHECK;
32558c2ecf20Sopenharmony_ci
32568c2ecf20Sopenharmony_cistatic int snd_hdsp_create_controls(struct snd_card *card, struct hdsp *hdsp)
32578c2ecf20Sopenharmony_ci{
32588c2ecf20Sopenharmony_ci	unsigned int idx;
32598c2ecf20Sopenharmony_ci	int err;
32608c2ecf20Sopenharmony_ci	struct snd_kcontrol *kctl;
32618c2ecf20Sopenharmony_ci
32628c2ecf20Sopenharmony_ci	if (hdsp->io_type == RPM) {
32638c2ecf20Sopenharmony_ci		/* RPM Bypass, Disconnect and Input switches */
32648c2ecf20Sopenharmony_ci		for (idx = 0; idx < ARRAY_SIZE(snd_hdsp_rpm_controls); idx++) {
32658c2ecf20Sopenharmony_ci			err = snd_ctl_add(card, kctl = snd_ctl_new1(&snd_hdsp_rpm_controls[idx], hdsp));
32668c2ecf20Sopenharmony_ci			if (err < 0)
32678c2ecf20Sopenharmony_ci				return err;
32688c2ecf20Sopenharmony_ci		}
32698c2ecf20Sopenharmony_ci		return 0;
32708c2ecf20Sopenharmony_ci	}
32718c2ecf20Sopenharmony_ci
32728c2ecf20Sopenharmony_ci	for (idx = 0; idx < ARRAY_SIZE(snd_hdsp_controls); idx++) {
32738c2ecf20Sopenharmony_ci		if ((err = snd_ctl_add(card, kctl = snd_ctl_new1(&snd_hdsp_controls[idx], hdsp))) < 0)
32748c2ecf20Sopenharmony_ci			return err;
32758c2ecf20Sopenharmony_ci		if (idx == 1)	/* IEC958 (S/PDIF) Stream */
32768c2ecf20Sopenharmony_ci			hdsp->spdif_ctl = kctl;
32778c2ecf20Sopenharmony_ci	}
32788c2ecf20Sopenharmony_ci
32798c2ecf20Sopenharmony_ci	/* ADAT SyncCheck status */
32808c2ecf20Sopenharmony_ci	snd_hdsp_adat_sync_check.name = "ADAT Lock Status";
32818c2ecf20Sopenharmony_ci	snd_hdsp_adat_sync_check.index = 1;
32828c2ecf20Sopenharmony_ci	if ((err = snd_ctl_add (card, kctl = snd_ctl_new1(&snd_hdsp_adat_sync_check, hdsp))))
32838c2ecf20Sopenharmony_ci		return err;
32848c2ecf20Sopenharmony_ci	if (hdsp->io_type == Digiface || hdsp->io_type == H9652) {
32858c2ecf20Sopenharmony_ci		for (idx = 1; idx < 3; ++idx) {
32868c2ecf20Sopenharmony_ci			snd_hdsp_adat_sync_check.index = idx+1;
32878c2ecf20Sopenharmony_ci			if ((err = snd_ctl_add (card, kctl = snd_ctl_new1(&snd_hdsp_adat_sync_check, hdsp))))
32888c2ecf20Sopenharmony_ci				return err;
32898c2ecf20Sopenharmony_ci		}
32908c2ecf20Sopenharmony_ci	}
32918c2ecf20Sopenharmony_ci
32928c2ecf20Sopenharmony_ci	/* DA, AD and Phone gain and XLR breakout cable controls for H9632 cards */
32938c2ecf20Sopenharmony_ci	if (hdsp->io_type == H9632) {
32948c2ecf20Sopenharmony_ci		for (idx = 0; idx < ARRAY_SIZE(snd_hdsp_9632_controls); idx++) {
32958c2ecf20Sopenharmony_ci			if ((err = snd_ctl_add(card, kctl = snd_ctl_new1(&snd_hdsp_9632_controls[idx], hdsp))) < 0)
32968c2ecf20Sopenharmony_ci				return err;
32978c2ecf20Sopenharmony_ci		}
32988c2ecf20Sopenharmony_ci	}
32998c2ecf20Sopenharmony_ci
33008c2ecf20Sopenharmony_ci	/* AEB control for H96xx card */
33018c2ecf20Sopenharmony_ci	if (hdsp->io_type == H9632 || hdsp->io_type == H9652) {
33028c2ecf20Sopenharmony_ci		if ((err = snd_ctl_add(card, kctl = snd_ctl_new1(&snd_hdsp_96xx_aeb, hdsp))) < 0)
33038c2ecf20Sopenharmony_ci				return err;
33048c2ecf20Sopenharmony_ci	}
33058c2ecf20Sopenharmony_ci
33068c2ecf20Sopenharmony_ci	return 0;
33078c2ecf20Sopenharmony_ci}
33088c2ecf20Sopenharmony_ci
33098c2ecf20Sopenharmony_ci/*------------------------------------------------------------
33108c2ecf20Sopenharmony_ci   /proc interface
33118c2ecf20Sopenharmony_ci ------------------------------------------------------------*/
33128c2ecf20Sopenharmony_ci
33138c2ecf20Sopenharmony_cistatic void
33148c2ecf20Sopenharmony_cisnd_hdsp_proc_read(struct snd_info_entry *entry, struct snd_info_buffer *buffer)
33158c2ecf20Sopenharmony_ci{
33168c2ecf20Sopenharmony_ci	struct hdsp *hdsp = entry->private_data;
33178c2ecf20Sopenharmony_ci	unsigned int status;
33188c2ecf20Sopenharmony_ci	unsigned int status2;
33198c2ecf20Sopenharmony_ci	char *pref_sync_ref;
33208c2ecf20Sopenharmony_ci	char *autosync_ref;
33218c2ecf20Sopenharmony_ci	char *system_clock_mode;
33228c2ecf20Sopenharmony_ci	char *clock_source;
33238c2ecf20Sopenharmony_ci	int x;
33248c2ecf20Sopenharmony_ci
33258c2ecf20Sopenharmony_ci	status = hdsp_read(hdsp, HDSP_statusRegister);
33268c2ecf20Sopenharmony_ci	status2 = hdsp_read(hdsp, HDSP_status2Register);
33278c2ecf20Sopenharmony_ci
33288c2ecf20Sopenharmony_ci	snd_iprintf(buffer, "%s (Card #%d)\n", hdsp->card_name,
33298c2ecf20Sopenharmony_ci		    hdsp->card->number + 1);
33308c2ecf20Sopenharmony_ci	snd_iprintf(buffer, "Buffers: capture %p playback %p\n",
33318c2ecf20Sopenharmony_ci		    hdsp->capture_buffer, hdsp->playback_buffer);
33328c2ecf20Sopenharmony_ci	snd_iprintf(buffer, "IRQ: %d Registers bus: 0x%lx VM: 0x%lx\n",
33338c2ecf20Sopenharmony_ci		    hdsp->irq, hdsp->port, (unsigned long)hdsp->iobase);
33348c2ecf20Sopenharmony_ci	snd_iprintf(buffer, "Control register: 0x%x\n", hdsp->control_register);
33358c2ecf20Sopenharmony_ci	snd_iprintf(buffer, "Control2 register: 0x%x\n",
33368c2ecf20Sopenharmony_ci		    hdsp->control2_register);
33378c2ecf20Sopenharmony_ci	snd_iprintf(buffer, "Status register: 0x%x\n", status);
33388c2ecf20Sopenharmony_ci	snd_iprintf(buffer, "Status2 register: 0x%x\n", status2);
33398c2ecf20Sopenharmony_ci
33408c2ecf20Sopenharmony_ci	if (hdsp_check_for_iobox(hdsp)) {
33418c2ecf20Sopenharmony_ci		snd_iprintf(buffer, "No I/O box connected.\n"
33428c2ecf20Sopenharmony_ci			    "Please connect one and upload firmware.\n");
33438c2ecf20Sopenharmony_ci		return;
33448c2ecf20Sopenharmony_ci	}
33458c2ecf20Sopenharmony_ci
33468c2ecf20Sopenharmony_ci	if (hdsp_check_for_firmware(hdsp, 0)) {
33478c2ecf20Sopenharmony_ci		if (hdsp->state & HDSP_FirmwareCached) {
33488c2ecf20Sopenharmony_ci			if (snd_hdsp_load_firmware_from_cache(hdsp) != 0) {
33498c2ecf20Sopenharmony_ci				snd_iprintf(buffer, "Firmware loading from "
33508c2ecf20Sopenharmony_ci					    "cache failed, "
33518c2ecf20Sopenharmony_ci					    "please upload manually.\n");
33528c2ecf20Sopenharmony_ci				return;
33538c2ecf20Sopenharmony_ci			}
33548c2ecf20Sopenharmony_ci		} else {
33558c2ecf20Sopenharmony_ci			int err;
33568c2ecf20Sopenharmony_ci
33578c2ecf20Sopenharmony_ci			err = hdsp_request_fw_loader(hdsp);
33588c2ecf20Sopenharmony_ci			if (err < 0) {
33598c2ecf20Sopenharmony_ci				snd_iprintf(buffer,
33608c2ecf20Sopenharmony_ci					    "No firmware loaded nor cached, "
33618c2ecf20Sopenharmony_ci					    "please upload firmware.\n");
33628c2ecf20Sopenharmony_ci				return;
33638c2ecf20Sopenharmony_ci			}
33648c2ecf20Sopenharmony_ci		}
33658c2ecf20Sopenharmony_ci	}
33668c2ecf20Sopenharmony_ci
33678c2ecf20Sopenharmony_ci	snd_iprintf(buffer, "FIFO status: %d\n", hdsp_read(hdsp, HDSP_fifoStatus) & 0xff);
33688c2ecf20Sopenharmony_ci	snd_iprintf(buffer, "MIDI1 Output status: 0x%x\n", hdsp_read(hdsp, HDSP_midiStatusOut0));
33698c2ecf20Sopenharmony_ci	snd_iprintf(buffer, "MIDI1 Input status: 0x%x\n", hdsp_read(hdsp, HDSP_midiStatusIn0));
33708c2ecf20Sopenharmony_ci	snd_iprintf(buffer, "MIDI2 Output status: 0x%x\n", hdsp_read(hdsp, HDSP_midiStatusOut1));
33718c2ecf20Sopenharmony_ci	snd_iprintf(buffer, "MIDI2 Input status: 0x%x\n", hdsp_read(hdsp, HDSP_midiStatusIn1));
33728c2ecf20Sopenharmony_ci	snd_iprintf(buffer, "Use Midi Tasklet: %s\n", hdsp->use_midi_work ? "on" : "off");
33738c2ecf20Sopenharmony_ci
33748c2ecf20Sopenharmony_ci	snd_iprintf(buffer, "\n");
33758c2ecf20Sopenharmony_ci
33768c2ecf20Sopenharmony_ci	x = 1 << (6 + hdsp_decode_latency(hdsp->control_register & HDSP_LatencyMask));
33778c2ecf20Sopenharmony_ci
33788c2ecf20Sopenharmony_ci	snd_iprintf(buffer, "Buffer Size (Latency): %d samples (2 periods of %lu bytes)\n", x, (unsigned long) hdsp->period_bytes);
33798c2ecf20Sopenharmony_ci	snd_iprintf(buffer, "Hardware pointer (frames): %ld\n", hdsp_hw_pointer(hdsp));
33808c2ecf20Sopenharmony_ci	snd_iprintf(buffer, "Precise pointer: %s\n", hdsp->precise_ptr ? "on" : "off");
33818c2ecf20Sopenharmony_ci	snd_iprintf(buffer, "Line out: %s\n", (hdsp->control_register & HDSP_LineOut) ? "on" : "off");
33828c2ecf20Sopenharmony_ci
33838c2ecf20Sopenharmony_ci	snd_iprintf(buffer, "Firmware version: %d\n", (status2&HDSP_version0)|(status2&HDSP_version1)<<1|(status2&HDSP_version2)<<2);
33848c2ecf20Sopenharmony_ci
33858c2ecf20Sopenharmony_ci	snd_iprintf(buffer, "\n");
33868c2ecf20Sopenharmony_ci
33878c2ecf20Sopenharmony_ci	switch (hdsp_clock_source(hdsp)) {
33888c2ecf20Sopenharmony_ci	case HDSP_CLOCK_SOURCE_AUTOSYNC:
33898c2ecf20Sopenharmony_ci		clock_source = "AutoSync";
33908c2ecf20Sopenharmony_ci		break;
33918c2ecf20Sopenharmony_ci	case HDSP_CLOCK_SOURCE_INTERNAL_32KHZ:
33928c2ecf20Sopenharmony_ci		clock_source = "Internal 32 kHz";
33938c2ecf20Sopenharmony_ci		break;
33948c2ecf20Sopenharmony_ci	case HDSP_CLOCK_SOURCE_INTERNAL_44_1KHZ:
33958c2ecf20Sopenharmony_ci		clock_source = "Internal 44.1 kHz";
33968c2ecf20Sopenharmony_ci		break;
33978c2ecf20Sopenharmony_ci	case HDSP_CLOCK_SOURCE_INTERNAL_48KHZ:
33988c2ecf20Sopenharmony_ci		clock_source = "Internal 48 kHz";
33998c2ecf20Sopenharmony_ci		break;
34008c2ecf20Sopenharmony_ci	case HDSP_CLOCK_SOURCE_INTERNAL_64KHZ:
34018c2ecf20Sopenharmony_ci		clock_source = "Internal 64 kHz";
34028c2ecf20Sopenharmony_ci		break;
34038c2ecf20Sopenharmony_ci	case HDSP_CLOCK_SOURCE_INTERNAL_88_2KHZ:
34048c2ecf20Sopenharmony_ci		clock_source = "Internal 88.2 kHz";
34058c2ecf20Sopenharmony_ci		break;
34068c2ecf20Sopenharmony_ci	case HDSP_CLOCK_SOURCE_INTERNAL_96KHZ:
34078c2ecf20Sopenharmony_ci		clock_source = "Internal 96 kHz";
34088c2ecf20Sopenharmony_ci		break;
34098c2ecf20Sopenharmony_ci	case HDSP_CLOCK_SOURCE_INTERNAL_128KHZ:
34108c2ecf20Sopenharmony_ci		clock_source = "Internal 128 kHz";
34118c2ecf20Sopenharmony_ci		break;
34128c2ecf20Sopenharmony_ci	case HDSP_CLOCK_SOURCE_INTERNAL_176_4KHZ:
34138c2ecf20Sopenharmony_ci		clock_source = "Internal 176.4 kHz";
34148c2ecf20Sopenharmony_ci		break;
34158c2ecf20Sopenharmony_ci		case HDSP_CLOCK_SOURCE_INTERNAL_192KHZ:
34168c2ecf20Sopenharmony_ci		clock_source = "Internal 192 kHz";
34178c2ecf20Sopenharmony_ci		break;
34188c2ecf20Sopenharmony_ci	default:
34198c2ecf20Sopenharmony_ci		clock_source = "Error";
34208c2ecf20Sopenharmony_ci	}
34218c2ecf20Sopenharmony_ci	snd_iprintf (buffer, "Sample Clock Source: %s\n", clock_source);
34228c2ecf20Sopenharmony_ci
34238c2ecf20Sopenharmony_ci	if (hdsp_system_clock_mode(hdsp))
34248c2ecf20Sopenharmony_ci		system_clock_mode = "Slave";
34258c2ecf20Sopenharmony_ci	else
34268c2ecf20Sopenharmony_ci		system_clock_mode = "Master";
34278c2ecf20Sopenharmony_ci
34288c2ecf20Sopenharmony_ci	switch (hdsp_pref_sync_ref (hdsp)) {
34298c2ecf20Sopenharmony_ci	case HDSP_SYNC_FROM_WORD:
34308c2ecf20Sopenharmony_ci		pref_sync_ref = "Word Clock";
34318c2ecf20Sopenharmony_ci		break;
34328c2ecf20Sopenharmony_ci	case HDSP_SYNC_FROM_ADAT_SYNC:
34338c2ecf20Sopenharmony_ci		pref_sync_ref = "ADAT Sync";
34348c2ecf20Sopenharmony_ci		break;
34358c2ecf20Sopenharmony_ci	case HDSP_SYNC_FROM_SPDIF:
34368c2ecf20Sopenharmony_ci		pref_sync_ref = "SPDIF";
34378c2ecf20Sopenharmony_ci		break;
34388c2ecf20Sopenharmony_ci	case HDSP_SYNC_FROM_ADAT1:
34398c2ecf20Sopenharmony_ci		pref_sync_ref = "ADAT1";
34408c2ecf20Sopenharmony_ci		break;
34418c2ecf20Sopenharmony_ci	case HDSP_SYNC_FROM_ADAT2:
34428c2ecf20Sopenharmony_ci		pref_sync_ref = "ADAT2";
34438c2ecf20Sopenharmony_ci		break;
34448c2ecf20Sopenharmony_ci	case HDSP_SYNC_FROM_ADAT3:
34458c2ecf20Sopenharmony_ci		pref_sync_ref = "ADAT3";
34468c2ecf20Sopenharmony_ci		break;
34478c2ecf20Sopenharmony_ci	default:
34488c2ecf20Sopenharmony_ci		pref_sync_ref = "Word Clock";
34498c2ecf20Sopenharmony_ci		break;
34508c2ecf20Sopenharmony_ci	}
34518c2ecf20Sopenharmony_ci	snd_iprintf (buffer, "Preferred Sync Reference: %s\n", pref_sync_ref);
34528c2ecf20Sopenharmony_ci
34538c2ecf20Sopenharmony_ci	switch (hdsp_autosync_ref (hdsp)) {
34548c2ecf20Sopenharmony_ci	case HDSP_AUTOSYNC_FROM_WORD:
34558c2ecf20Sopenharmony_ci		autosync_ref = "Word Clock";
34568c2ecf20Sopenharmony_ci		break;
34578c2ecf20Sopenharmony_ci	case HDSP_AUTOSYNC_FROM_ADAT_SYNC:
34588c2ecf20Sopenharmony_ci		autosync_ref = "ADAT Sync";
34598c2ecf20Sopenharmony_ci		break;
34608c2ecf20Sopenharmony_ci	case HDSP_AUTOSYNC_FROM_SPDIF:
34618c2ecf20Sopenharmony_ci		autosync_ref = "SPDIF";
34628c2ecf20Sopenharmony_ci		break;
34638c2ecf20Sopenharmony_ci	case HDSP_AUTOSYNC_FROM_NONE:
34648c2ecf20Sopenharmony_ci		autosync_ref = "None";
34658c2ecf20Sopenharmony_ci		break;
34668c2ecf20Sopenharmony_ci	case HDSP_AUTOSYNC_FROM_ADAT1:
34678c2ecf20Sopenharmony_ci		autosync_ref = "ADAT1";
34688c2ecf20Sopenharmony_ci		break;
34698c2ecf20Sopenharmony_ci	case HDSP_AUTOSYNC_FROM_ADAT2:
34708c2ecf20Sopenharmony_ci		autosync_ref = "ADAT2";
34718c2ecf20Sopenharmony_ci		break;
34728c2ecf20Sopenharmony_ci	case HDSP_AUTOSYNC_FROM_ADAT3:
34738c2ecf20Sopenharmony_ci		autosync_ref = "ADAT3";
34748c2ecf20Sopenharmony_ci		break;
34758c2ecf20Sopenharmony_ci	default:
34768c2ecf20Sopenharmony_ci		autosync_ref = "---";
34778c2ecf20Sopenharmony_ci		break;
34788c2ecf20Sopenharmony_ci	}
34798c2ecf20Sopenharmony_ci	snd_iprintf (buffer, "AutoSync Reference: %s\n", autosync_ref);
34808c2ecf20Sopenharmony_ci
34818c2ecf20Sopenharmony_ci	snd_iprintf (buffer, "AutoSync Frequency: %d\n", hdsp_external_sample_rate(hdsp));
34828c2ecf20Sopenharmony_ci
34838c2ecf20Sopenharmony_ci	snd_iprintf (buffer, "System Clock Mode: %s\n", system_clock_mode);
34848c2ecf20Sopenharmony_ci
34858c2ecf20Sopenharmony_ci	snd_iprintf (buffer, "System Clock Frequency: %d\n", hdsp->system_sample_rate);
34868c2ecf20Sopenharmony_ci	snd_iprintf (buffer, "System Clock Locked: %s\n", hdsp->clock_source_locked ? "Yes" : "No");
34878c2ecf20Sopenharmony_ci
34888c2ecf20Sopenharmony_ci	snd_iprintf(buffer, "\n");
34898c2ecf20Sopenharmony_ci
34908c2ecf20Sopenharmony_ci	if (hdsp->io_type != RPM) {
34918c2ecf20Sopenharmony_ci		switch (hdsp_spdif_in(hdsp)) {
34928c2ecf20Sopenharmony_ci		case HDSP_SPDIFIN_OPTICAL:
34938c2ecf20Sopenharmony_ci			snd_iprintf(buffer, "IEC958 input: Optical\n");
34948c2ecf20Sopenharmony_ci			break;
34958c2ecf20Sopenharmony_ci		case HDSP_SPDIFIN_COAXIAL:
34968c2ecf20Sopenharmony_ci			snd_iprintf(buffer, "IEC958 input: Coaxial\n");
34978c2ecf20Sopenharmony_ci			break;
34988c2ecf20Sopenharmony_ci		case HDSP_SPDIFIN_INTERNAL:
34998c2ecf20Sopenharmony_ci			snd_iprintf(buffer, "IEC958 input: Internal\n");
35008c2ecf20Sopenharmony_ci			break;
35018c2ecf20Sopenharmony_ci		case HDSP_SPDIFIN_AES:
35028c2ecf20Sopenharmony_ci			snd_iprintf(buffer, "IEC958 input: AES\n");
35038c2ecf20Sopenharmony_ci			break;
35048c2ecf20Sopenharmony_ci		default:
35058c2ecf20Sopenharmony_ci			snd_iprintf(buffer, "IEC958 input: ???\n");
35068c2ecf20Sopenharmony_ci			break;
35078c2ecf20Sopenharmony_ci		}
35088c2ecf20Sopenharmony_ci	}
35098c2ecf20Sopenharmony_ci
35108c2ecf20Sopenharmony_ci	if (RPM == hdsp->io_type) {
35118c2ecf20Sopenharmony_ci		if (hdsp->control_register & HDSP_RPM_Bypass)
35128c2ecf20Sopenharmony_ci			snd_iprintf(buffer, "RPM Bypass: disabled\n");
35138c2ecf20Sopenharmony_ci		else
35148c2ecf20Sopenharmony_ci			snd_iprintf(buffer, "RPM Bypass: enabled\n");
35158c2ecf20Sopenharmony_ci		if (hdsp->control_register & HDSP_RPM_Disconnect)
35168c2ecf20Sopenharmony_ci			snd_iprintf(buffer, "RPM disconnected\n");
35178c2ecf20Sopenharmony_ci		else
35188c2ecf20Sopenharmony_ci			snd_iprintf(buffer, "RPM connected\n");
35198c2ecf20Sopenharmony_ci
35208c2ecf20Sopenharmony_ci		switch (hdsp->control_register & HDSP_RPM_Inp12) {
35218c2ecf20Sopenharmony_ci		case HDSP_RPM_Inp12_Phon_6dB:
35228c2ecf20Sopenharmony_ci			snd_iprintf(buffer, "Input 1/2: Phono, 6dB\n");
35238c2ecf20Sopenharmony_ci			break;
35248c2ecf20Sopenharmony_ci		case HDSP_RPM_Inp12_Phon_0dB:
35258c2ecf20Sopenharmony_ci			snd_iprintf(buffer, "Input 1/2: Phono, 0dB\n");
35268c2ecf20Sopenharmony_ci			break;
35278c2ecf20Sopenharmony_ci		case HDSP_RPM_Inp12_Phon_n6dB:
35288c2ecf20Sopenharmony_ci			snd_iprintf(buffer, "Input 1/2: Phono, -6dB\n");
35298c2ecf20Sopenharmony_ci			break;
35308c2ecf20Sopenharmony_ci		case HDSP_RPM_Inp12_Line_0dB:
35318c2ecf20Sopenharmony_ci			snd_iprintf(buffer, "Input 1/2: Line, 0dB\n");
35328c2ecf20Sopenharmony_ci			break;
35338c2ecf20Sopenharmony_ci		case HDSP_RPM_Inp12_Line_n6dB:
35348c2ecf20Sopenharmony_ci			snd_iprintf(buffer, "Input 1/2: Line, -6dB\n");
35358c2ecf20Sopenharmony_ci			break;
35368c2ecf20Sopenharmony_ci		default:
35378c2ecf20Sopenharmony_ci			snd_iprintf(buffer, "Input 1/2: ???\n");
35388c2ecf20Sopenharmony_ci		}
35398c2ecf20Sopenharmony_ci
35408c2ecf20Sopenharmony_ci		switch (hdsp->control_register & HDSP_RPM_Inp34) {
35418c2ecf20Sopenharmony_ci		case HDSP_RPM_Inp34_Phon_6dB:
35428c2ecf20Sopenharmony_ci			snd_iprintf(buffer, "Input 3/4: Phono, 6dB\n");
35438c2ecf20Sopenharmony_ci			break;
35448c2ecf20Sopenharmony_ci		case HDSP_RPM_Inp34_Phon_0dB:
35458c2ecf20Sopenharmony_ci			snd_iprintf(buffer, "Input 3/4: Phono, 0dB\n");
35468c2ecf20Sopenharmony_ci			break;
35478c2ecf20Sopenharmony_ci		case HDSP_RPM_Inp34_Phon_n6dB:
35488c2ecf20Sopenharmony_ci			snd_iprintf(buffer, "Input 3/4: Phono, -6dB\n");
35498c2ecf20Sopenharmony_ci			break;
35508c2ecf20Sopenharmony_ci		case HDSP_RPM_Inp34_Line_0dB:
35518c2ecf20Sopenharmony_ci			snd_iprintf(buffer, "Input 3/4: Line, 0dB\n");
35528c2ecf20Sopenharmony_ci			break;
35538c2ecf20Sopenharmony_ci		case HDSP_RPM_Inp34_Line_n6dB:
35548c2ecf20Sopenharmony_ci			snd_iprintf(buffer, "Input 3/4: Line, -6dB\n");
35558c2ecf20Sopenharmony_ci			break;
35568c2ecf20Sopenharmony_ci		default:
35578c2ecf20Sopenharmony_ci			snd_iprintf(buffer, "Input 3/4: ???\n");
35588c2ecf20Sopenharmony_ci		}
35598c2ecf20Sopenharmony_ci
35608c2ecf20Sopenharmony_ci	} else {
35618c2ecf20Sopenharmony_ci		if (hdsp->control_register & HDSP_SPDIFOpticalOut)
35628c2ecf20Sopenharmony_ci			snd_iprintf(buffer, "IEC958 output: Coaxial & ADAT1\n");
35638c2ecf20Sopenharmony_ci		else
35648c2ecf20Sopenharmony_ci			snd_iprintf(buffer, "IEC958 output: Coaxial only\n");
35658c2ecf20Sopenharmony_ci
35668c2ecf20Sopenharmony_ci		if (hdsp->control_register & HDSP_SPDIFProfessional)
35678c2ecf20Sopenharmony_ci			snd_iprintf(buffer, "IEC958 quality: Professional\n");
35688c2ecf20Sopenharmony_ci		else
35698c2ecf20Sopenharmony_ci			snd_iprintf(buffer, "IEC958 quality: Consumer\n");
35708c2ecf20Sopenharmony_ci
35718c2ecf20Sopenharmony_ci		if (hdsp->control_register & HDSP_SPDIFEmphasis)
35728c2ecf20Sopenharmony_ci			snd_iprintf(buffer, "IEC958 emphasis: on\n");
35738c2ecf20Sopenharmony_ci		else
35748c2ecf20Sopenharmony_ci			snd_iprintf(buffer, "IEC958 emphasis: off\n");
35758c2ecf20Sopenharmony_ci
35768c2ecf20Sopenharmony_ci		if (hdsp->control_register & HDSP_SPDIFNonAudio)
35778c2ecf20Sopenharmony_ci			snd_iprintf(buffer, "IEC958 NonAudio: on\n");
35788c2ecf20Sopenharmony_ci		else
35798c2ecf20Sopenharmony_ci			snd_iprintf(buffer, "IEC958 NonAudio: off\n");
35808c2ecf20Sopenharmony_ci		x = hdsp_spdif_sample_rate(hdsp);
35818c2ecf20Sopenharmony_ci		if (x != 0)
35828c2ecf20Sopenharmony_ci			snd_iprintf(buffer, "IEC958 sample rate: %d\n", x);
35838c2ecf20Sopenharmony_ci		else
35848c2ecf20Sopenharmony_ci			snd_iprintf(buffer, "IEC958 sample rate: Error flag set\n");
35858c2ecf20Sopenharmony_ci	}
35868c2ecf20Sopenharmony_ci	snd_iprintf(buffer, "\n");
35878c2ecf20Sopenharmony_ci
35888c2ecf20Sopenharmony_ci	/* Sync Check */
35898c2ecf20Sopenharmony_ci	x = status & HDSP_Sync0;
35908c2ecf20Sopenharmony_ci	if (status & HDSP_Lock0)
35918c2ecf20Sopenharmony_ci		snd_iprintf(buffer, "ADAT1: %s\n", x ? "Sync" : "Lock");
35928c2ecf20Sopenharmony_ci	else
35938c2ecf20Sopenharmony_ci		snd_iprintf(buffer, "ADAT1: No Lock\n");
35948c2ecf20Sopenharmony_ci
35958c2ecf20Sopenharmony_ci	switch (hdsp->io_type) {
35968c2ecf20Sopenharmony_ci	case Digiface:
35978c2ecf20Sopenharmony_ci	case H9652:
35988c2ecf20Sopenharmony_ci		x = status & HDSP_Sync1;
35998c2ecf20Sopenharmony_ci		if (status & HDSP_Lock1)
36008c2ecf20Sopenharmony_ci			snd_iprintf(buffer, "ADAT2: %s\n", x ? "Sync" : "Lock");
36018c2ecf20Sopenharmony_ci		else
36028c2ecf20Sopenharmony_ci			snd_iprintf(buffer, "ADAT2: No Lock\n");
36038c2ecf20Sopenharmony_ci		x = status & HDSP_Sync2;
36048c2ecf20Sopenharmony_ci		if (status & HDSP_Lock2)
36058c2ecf20Sopenharmony_ci			snd_iprintf(buffer, "ADAT3: %s\n", x ? "Sync" : "Lock");
36068c2ecf20Sopenharmony_ci		else
36078c2ecf20Sopenharmony_ci			snd_iprintf(buffer, "ADAT3: No Lock\n");
36088c2ecf20Sopenharmony_ci		break;
36098c2ecf20Sopenharmony_ci	default:
36108c2ecf20Sopenharmony_ci		/* relax */
36118c2ecf20Sopenharmony_ci		break;
36128c2ecf20Sopenharmony_ci	}
36138c2ecf20Sopenharmony_ci
36148c2ecf20Sopenharmony_ci	x = status & HDSP_SPDIFSync;
36158c2ecf20Sopenharmony_ci	if (status & HDSP_SPDIFErrorFlag)
36168c2ecf20Sopenharmony_ci		snd_iprintf (buffer, "SPDIF: No Lock\n");
36178c2ecf20Sopenharmony_ci	else
36188c2ecf20Sopenharmony_ci		snd_iprintf (buffer, "SPDIF: %s\n", x ? "Sync" : "Lock");
36198c2ecf20Sopenharmony_ci
36208c2ecf20Sopenharmony_ci	x = status2 & HDSP_wc_sync;
36218c2ecf20Sopenharmony_ci	if (status2 & HDSP_wc_lock)
36228c2ecf20Sopenharmony_ci		snd_iprintf (buffer, "Word Clock: %s\n", x ? "Sync" : "Lock");
36238c2ecf20Sopenharmony_ci	else
36248c2ecf20Sopenharmony_ci		snd_iprintf (buffer, "Word Clock: No Lock\n");
36258c2ecf20Sopenharmony_ci
36268c2ecf20Sopenharmony_ci	x = status & HDSP_TimecodeSync;
36278c2ecf20Sopenharmony_ci	if (status & HDSP_TimecodeLock)
36288c2ecf20Sopenharmony_ci		snd_iprintf(buffer, "ADAT Sync: %s\n", x ? "Sync" : "Lock");
36298c2ecf20Sopenharmony_ci	else
36308c2ecf20Sopenharmony_ci		snd_iprintf(buffer, "ADAT Sync: No Lock\n");
36318c2ecf20Sopenharmony_ci
36328c2ecf20Sopenharmony_ci	snd_iprintf(buffer, "\n");
36338c2ecf20Sopenharmony_ci
36348c2ecf20Sopenharmony_ci	/* Informations about H9632 specific controls */
36358c2ecf20Sopenharmony_ci	if (hdsp->io_type == H9632) {
36368c2ecf20Sopenharmony_ci		char *tmp;
36378c2ecf20Sopenharmony_ci
36388c2ecf20Sopenharmony_ci		switch (hdsp_ad_gain(hdsp)) {
36398c2ecf20Sopenharmony_ci		case 0:
36408c2ecf20Sopenharmony_ci			tmp = "-10 dBV";
36418c2ecf20Sopenharmony_ci			break;
36428c2ecf20Sopenharmony_ci		case 1:
36438c2ecf20Sopenharmony_ci			tmp = "+4 dBu";
36448c2ecf20Sopenharmony_ci			break;
36458c2ecf20Sopenharmony_ci		default:
36468c2ecf20Sopenharmony_ci			tmp = "Lo Gain";
36478c2ecf20Sopenharmony_ci			break;
36488c2ecf20Sopenharmony_ci		}
36498c2ecf20Sopenharmony_ci		snd_iprintf(buffer, "AD Gain : %s\n", tmp);
36508c2ecf20Sopenharmony_ci
36518c2ecf20Sopenharmony_ci		switch (hdsp_da_gain(hdsp)) {
36528c2ecf20Sopenharmony_ci		case 0:
36538c2ecf20Sopenharmony_ci			tmp = "Hi Gain";
36548c2ecf20Sopenharmony_ci			break;
36558c2ecf20Sopenharmony_ci		case 1:
36568c2ecf20Sopenharmony_ci			tmp = "+4 dBu";
36578c2ecf20Sopenharmony_ci			break;
36588c2ecf20Sopenharmony_ci		default:
36598c2ecf20Sopenharmony_ci			tmp = "-10 dBV";
36608c2ecf20Sopenharmony_ci			break;
36618c2ecf20Sopenharmony_ci		}
36628c2ecf20Sopenharmony_ci		snd_iprintf(buffer, "DA Gain : %s\n", tmp);
36638c2ecf20Sopenharmony_ci
36648c2ecf20Sopenharmony_ci		switch (hdsp_phone_gain(hdsp)) {
36658c2ecf20Sopenharmony_ci		case 0:
36668c2ecf20Sopenharmony_ci			tmp = "0 dB";
36678c2ecf20Sopenharmony_ci			break;
36688c2ecf20Sopenharmony_ci		case 1:
36698c2ecf20Sopenharmony_ci			tmp = "-6 dB";
36708c2ecf20Sopenharmony_ci			break;
36718c2ecf20Sopenharmony_ci		default:
36728c2ecf20Sopenharmony_ci			tmp = "-12 dB";
36738c2ecf20Sopenharmony_ci			break;
36748c2ecf20Sopenharmony_ci		}
36758c2ecf20Sopenharmony_ci		snd_iprintf(buffer, "Phones Gain : %s\n", tmp);
36768c2ecf20Sopenharmony_ci
36778c2ecf20Sopenharmony_ci		snd_iprintf(buffer, "XLR Breakout Cable : %s\n",
36788c2ecf20Sopenharmony_ci			hdsp_toggle_setting(hdsp, HDSP_XLRBreakoutCable) ?
36798c2ecf20Sopenharmony_ci			"yes" : "no");
36808c2ecf20Sopenharmony_ci
36818c2ecf20Sopenharmony_ci		if (hdsp->control_register & HDSP_AnalogExtensionBoard)
36828c2ecf20Sopenharmony_ci			snd_iprintf(buffer, "AEB : on (ADAT1 internal)\n");
36838c2ecf20Sopenharmony_ci		else
36848c2ecf20Sopenharmony_ci			snd_iprintf(buffer, "AEB : off (ADAT1 external)\n");
36858c2ecf20Sopenharmony_ci		snd_iprintf(buffer, "\n");
36868c2ecf20Sopenharmony_ci	}
36878c2ecf20Sopenharmony_ci
36888c2ecf20Sopenharmony_ci}
36898c2ecf20Sopenharmony_ci
36908c2ecf20Sopenharmony_cistatic void snd_hdsp_proc_init(struct hdsp *hdsp)
36918c2ecf20Sopenharmony_ci{
36928c2ecf20Sopenharmony_ci	snd_card_ro_proc_new(hdsp->card, "hdsp", hdsp, snd_hdsp_proc_read);
36938c2ecf20Sopenharmony_ci}
36948c2ecf20Sopenharmony_ci
36958c2ecf20Sopenharmony_cistatic void snd_hdsp_free_buffers(struct hdsp *hdsp)
36968c2ecf20Sopenharmony_ci{
36978c2ecf20Sopenharmony_ci	snd_hammerfall_free_buffer(&hdsp->capture_dma_buf, hdsp->pci);
36988c2ecf20Sopenharmony_ci	snd_hammerfall_free_buffer(&hdsp->playback_dma_buf, hdsp->pci);
36998c2ecf20Sopenharmony_ci}
37008c2ecf20Sopenharmony_ci
37018c2ecf20Sopenharmony_cistatic int snd_hdsp_initialize_memory(struct hdsp *hdsp)
37028c2ecf20Sopenharmony_ci{
37038c2ecf20Sopenharmony_ci	unsigned long pb_bus, cb_bus;
37048c2ecf20Sopenharmony_ci
37058c2ecf20Sopenharmony_ci	if (snd_hammerfall_get_buffer(hdsp->pci, &hdsp->capture_dma_buf, HDSP_DMA_AREA_BYTES) < 0 ||
37068c2ecf20Sopenharmony_ci	    snd_hammerfall_get_buffer(hdsp->pci, &hdsp->playback_dma_buf, HDSP_DMA_AREA_BYTES) < 0) {
37078c2ecf20Sopenharmony_ci		if (hdsp->capture_dma_buf.area)
37088c2ecf20Sopenharmony_ci			snd_dma_free_pages(&hdsp->capture_dma_buf);
37098c2ecf20Sopenharmony_ci		dev_err(hdsp->card->dev,
37108c2ecf20Sopenharmony_ci			"%s: no buffers available\n", hdsp->card_name);
37118c2ecf20Sopenharmony_ci		return -ENOMEM;
37128c2ecf20Sopenharmony_ci	}
37138c2ecf20Sopenharmony_ci
37148c2ecf20Sopenharmony_ci	/* Align to bus-space 64K boundary */
37158c2ecf20Sopenharmony_ci
37168c2ecf20Sopenharmony_ci	cb_bus = ALIGN(hdsp->capture_dma_buf.addr, 0x10000ul);
37178c2ecf20Sopenharmony_ci	pb_bus = ALIGN(hdsp->playback_dma_buf.addr, 0x10000ul);
37188c2ecf20Sopenharmony_ci
37198c2ecf20Sopenharmony_ci	/* Tell the card where it is */
37208c2ecf20Sopenharmony_ci
37218c2ecf20Sopenharmony_ci	hdsp_write(hdsp, HDSP_inputBufferAddress, cb_bus);
37228c2ecf20Sopenharmony_ci	hdsp_write(hdsp, HDSP_outputBufferAddress, pb_bus);
37238c2ecf20Sopenharmony_ci
37248c2ecf20Sopenharmony_ci	hdsp->capture_buffer = hdsp->capture_dma_buf.area + (cb_bus - hdsp->capture_dma_buf.addr);
37258c2ecf20Sopenharmony_ci	hdsp->playback_buffer = hdsp->playback_dma_buf.area + (pb_bus - hdsp->playback_dma_buf.addr);
37268c2ecf20Sopenharmony_ci
37278c2ecf20Sopenharmony_ci	return 0;
37288c2ecf20Sopenharmony_ci}
37298c2ecf20Sopenharmony_ci
37308c2ecf20Sopenharmony_cistatic int snd_hdsp_set_defaults(struct hdsp *hdsp)
37318c2ecf20Sopenharmony_ci{
37328c2ecf20Sopenharmony_ci	unsigned int i;
37338c2ecf20Sopenharmony_ci
37348c2ecf20Sopenharmony_ci	/* ASSUMPTION: hdsp->lock is either held, or
37358c2ecf20Sopenharmony_ci	   there is no need to hold it (e.g. during module
37368c2ecf20Sopenharmony_ci	   initialization).
37378c2ecf20Sopenharmony_ci	 */
37388c2ecf20Sopenharmony_ci
37398c2ecf20Sopenharmony_ci	/* set defaults:
37408c2ecf20Sopenharmony_ci
37418c2ecf20Sopenharmony_ci	   SPDIF Input via Coax
37428c2ecf20Sopenharmony_ci	   Master clock mode
37438c2ecf20Sopenharmony_ci	   maximum latency (7 => 2^7 = 8192 samples, 64Kbyte buffer,
37448c2ecf20Sopenharmony_ci	                    which implies 2 4096 sample, 32Kbyte periods).
37458c2ecf20Sopenharmony_ci           Enable line out.
37468c2ecf20Sopenharmony_ci	 */
37478c2ecf20Sopenharmony_ci
37488c2ecf20Sopenharmony_ci	hdsp->control_register = HDSP_ClockModeMaster |
37498c2ecf20Sopenharmony_ci		                 HDSP_SPDIFInputCoaxial |
37508c2ecf20Sopenharmony_ci		                 hdsp_encode_latency(7) |
37518c2ecf20Sopenharmony_ci		                 HDSP_LineOut;
37528c2ecf20Sopenharmony_ci
37538c2ecf20Sopenharmony_ci
37548c2ecf20Sopenharmony_ci	hdsp_write(hdsp, HDSP_controlRegister, hdsp->control_register);
37558c2ecf20Sopenharmony_ci
37568c2ecf20Sopenharmony_ci#ifdef SNDRV_BIG_ENDIAN
37578c2ecf20Sopenharmony_ci	hdsp->control2_register = HDSP_BIGENDIAN_MODE;
37588c2ecf20Sopenharmony_ci#else
37598c2ecf20Sopenharmony_ci	hdsp->control2_register = 0;
37608c2ecf20Sopenharmony_ci#endif
37618c2ecf20Sopenharmony_ci	if (hdsp->io_type == H9652)
37628c2ecf20Sopenharmony_ci	        snd_hdsp_9652_enable_mixer (hdsp);
37638c2ecf20Sopenharmony_ci	else
37648c2ecf20Sopenharmony_ci		hdsp_write (hdsp, HDSP_control2Reg, hdsp->control2_register);
37658c2ecf20Sopenharmony_ci
37668c2ecf20Sopenharmony_ci	hdsp_reset_hw_pointer(hdsp);
37678c2ecf20Sopenharmony_ci	hdsp_compute_period_size(hdsp);
37688c2ecf20Sopenharmony_ci
37698c2ecf20Sopenharmony_ci	/* silence everything */
37708c2ecf20Sopenharmony_ci
37718c2ecf20Sopenharmony_ci	for (i = 0; i < HDSP_MATRIX_MIXER_SIZE; ++i)
37728c2ecf20Sopenharmony_ci		hdsp->mixer_matrix[i] = MINUS_INFINITY_GAIN;
37738c2ecf20Sopenharmony_ci
37748c2ecf20Sopenharmony_ci	for (i = 0; i < ((hdsp->io_type == H9652 || hdsp->io_type == H9632) ? 1352 : HDSP_MATRIX_MIXER_SIZE); ++i) {
37758c2ecf20Sopenharmony_ci		if (hdsp_write_gain (hdsp, i, MINUS_INFINITY_GAIN))
37768c2ecf20Sopenharmony_ci			return -EIO;
37778c2ecf20Sopenharmony_ci	}
37788c2ecf20Sopenharmony_ci
37798c2ecf20Sopenharmony_ci	/* H9632 specific defaults */
37808c2ecf20Sopenharmony_ci	if (hdsp->io_type == H9632) {
37818c2ecf20Sopenharmony_ci		hdsp->control_register |= (HDSP_DAGainPlus4dBu | HDSP_ADGainPlus4dBu | HDSP_PhoneGain0dB);
37828c2ecf20Sopenharmony_ci		hdsp_write(hdsp, HDSP_controlRegister, hdsp->control_register);
37838c2ecf20Sopenharmony_ci	}
37848c2ecf20Sopenharmony_ci
37858c2ecf20Sopenharmony_ci	/* set a default rate so that the channel map is set up.
37868c2ecf20Sopenharmony_ci	 */
37878c2ecf20Sopenharmony_ci
37888c2ecf20Sopenharmony_ci	hdsp_set_rate(hdsp, 48000, 1);
37898c2ecf20Sopenharmony_ci
37908c2ecf20Sopenharmony_ci	return 0;
37918c2ecf20Sopenharmony_ci}
37928c2ecf20Sopenharmony_ci
37938c2ecf20Sopenharmony_cistatic void hdsp_midi_work(struct work_struct *work)
37948c2ecf20Sopenharmony_ci{
37958c2ecf20Sopenharmony_ci	struct hdsp *hdsp = container_of(work, struct hdsp, midi_work);
37968c2ecf20Sopenharmony_ci
37978c2ecf20Sopenharmony_ci	if (hdsp->midi[0].pending)
37988c2ecf20Sopenharmony_ci		snd_hdsp_midi_input_read (&hdsp->midi[0]);
37998c2ecf20Sopenharmony_ci	if (hdsp->midi[1].pending)
38008c2ecf20Sopenharmony_ci		snd_hdsp_midi_input_read (&hdsp->midi[1]);
38018c2ecf20Sopenharmony_ci}
38028c2ecf20Sopenharmony_ci
38038c2ecf20Sopenharmony_cistatic irqreturn_t snd_hdsp_interrupt(int irq, void *dev_id)
38048c2ecf20Sopenharmony_ci{
38058c2ecf20Sopenharmony_ci	struct hdsp *hdsp = (struct hdsp *) dev_id;
38068c2ecf20Sopenharmony_ci	unsigned int status;
38078c2ecf20Sopenharmony_ci	int audio;
38088c2ecf20Sopenharmony_ci	int midi0;
38098c2ecf20Sopenharmony_ci	int midi1;
38108c2ecf20Sopenharmony_ci	unsigned int midi0status;
38118c2ecf20Sopenharmony_ci	unsigned int midi1status;
38128c2ecf20Sopenharmony_ci	int schedule = 0;
38138c2ecf20Sopenharmony_ci
38148c2ecf20Sopenharmony_ci	status = hdsp_read(hdsp, HDSP_statusRegister);
38158c2ecf20Sopenharmony_ci
38168c2ecf20Sopenharmony_ci	audio = status & HDSP_audioIRQPending;
38178c2ecf20Sopenharmony_ci	midi0 = status & HDSP_midi0IRQPending;
38188c2ecf20Sopenharmony_ci	midi1 = status & HDSP_midi1IRQPending;
38198c2ecf20Sopenharmony_ci
38208c2ecf20Sopenharmony_ci	if (!audio && !midi0 && !midi1)
38218c2ecf20Sopenharmony_ci		return IRQ_NONE;
38228c2ecf20Sopenharmony_ci
38238c2ecf20Sopenharmony_ci	hdsp_write(hdsp, HDSP_interruptConfirmation, 0);
38248c2ecf20Sopenharmony_ci
38258c2ecf20Sopenharmony_ci	midi0status = hdsp_read (hdsp, HDSP_midiStatusIn0) & 0xff;
38268c2ecf20Sopenharmony_ci	midi1status = hdsp_read (hdsp, HDSP_midiStatusIn1) & 0xff;
38278c2ecf20Sopenharmony_ci
38288c2ecf20Sopenharmony_ci	if (!(hdsp->state & HDSP_InitializationComplete))
38298c2ecf20Sopenharmony_ci		return IRQ_HANDLED;
38308c2ecf20Sopenharmony_ci
38318c2ecf20Sopenharmony_ci	if (audio) {
38328c2ecf20Sopenharmony_ci		if (hdsp->capture_substream)
38338c2ecf20Sopenharmony_ci			snd_pcm_period_elapsed(hdsp->pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream);
38348c2ecf20Sopenharmony_ci
38358c2ecf20Sopenharmony_ci		if (hdsp->playback_substream)
38368c2ecf20Sopenharmony_ci			snd_pcm_period_elapsed(hdsp->pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream);
38378c2ecf20Sopenharmony_ci	}
38388c2ecf20Sopenharmony_ci
38398c2ecf20Sopenharmony_ci	if (midi0 && midi0status) {
38408c2ecf20Sopenharmony_ci		if (hdsp->use_midi_work) {
38418c2ecf20Sopenharmony_ci			/* we disable interrupts for this input until processing is done */
38428c2ecf20Sopenharmony_ci			hdsp->control_register &= ~HDSP_Midi0InterruptEnable;
38438c2ecf20Sopenharmony_ci			hdsp_write(hdsp, HDSP_controlRegister, hdsp->control_register);
38448c2ecf20Sopenharmony_ci			hdsp->midi[0].pending = 1;
38458c2ecf20Sopenharmony_ci			schedule = 1;
38468c2ecf20Sopenharmony_ci		} else {
38478c2ecf20Sopenharmony_ci			snd_hdsp_midi_input_read (&hdsp->midi[0]);
38488c2ecf20Sopenharmony_ci		}
38498c2ecf20Sopenharmony_ci	}
38508c2ecf20Sopenharmony_ci	if (hdsp->io_type != Multiface && hdsp->io_type != RPM && hdsp->io_type != H9632 && midi1 && midi1status) {
38518c2ecf20Sopenharmony_ci		if (hdsp->use_midi_work) {
38528c2ecf20Sopenharmony_ci			/* we disable interrupts for this input until processing is done */
38538c2ecf20Sopenharmony_ci			hdsp->control_register &= ~HDSP_Midi1InterruptEnable;
38548c2ecf20Sopenharmony_ci			hdsp_write(hdsp, HDSP_controlRegister, hdsp->control_register);
38558c2ecf20Sopenharmony_ci			hdsp->midi[1].pending = 1;
38568c2ecf20Sopenharmony_ci			schedule = 1;
38578c2ecf20Sopenharmony_ci		} else {
38588c2ecf20Sopenharmony_ci			snd_hdsp_midi_input_read (&hdsp->midi[1]);
38598c2ecf20Sopenharmony_ci		}
38608c2ecf20Sopenharmony_ci	}
38618c2ecf20Sopenharmony_ci	if (hdsp->use_midi_work && schedule)
38628c2ecf20Sopenharmony_ci		queue_work(system_highpri_wq, &hdsp->midi_work);
38638c2ecf20Sopenharmony_ci	return IRQ_HANDLED;
38648c2ecf20Sopenharmony_ci}
38658c2ecf20Sopenharmony_ci
38668c2ecf20Sopenharmony_cistatic snd_pcm_uframes_t snd_hdsp_hw_pointer(struct snd_pcm_substream *substream)
38678c2ecf20Sopenharmony_ci{
38688c2ecf20Sopenharmony_ci	struct hdsp *hdsp = snd_pcm_substream_chip(substream);
38698c2ecf20Sopenharmony_ci	return hdsp_hw_pointer(hdsp);
38708c2ecf20Sopenharmony_ci}
38718c2ecf20Sopenharmony_ci
38728c2ecf20Sopenharmony_cistatic signed char *hdsp_channel_buffer_location(struct hdsp *hdsp,
38738c2ecf20Sopenharmony_ci					     int stream,
38748c2ecf20Sopenharmony_ci					     int channel)
38758c2ecf20Sopenharmony_ci
38768c2ecf20Sopenharmony_ci{
38778c2ecf20Sopenharmony_ci	int mapped_channel;
38788c2ecf20Sopenharmony_ci
38798c2ecf20Sopenharmony_ci        if (snd_BUG_ON(channel < 0 || channel >= hdsp->max_channels))
38808c2ecf20Sopenharmony_ci		return NULL;
38818c2ecf20Sopenharmony_ci
38828c2ecf20Sopenharmony_ci	if ((mapped_channel = hdsp->channel_map[channel]) < 0)
38838c2ecf20Sopenharmony_ci		return NULL;
38848c2ecf20Sopenharmony_ci
38858c2ecf20Sopenharmony_ci	if (stream == SNDRV_PCM_STREAM_CAPTURE)
38868c2ecf20Sopenharmony_ci		return hdsp->capture_buffer + (mapped_channel * HDSP_CHANNEL_BUFFER_BYTES);
38878c2ecf20Sopenharmony_ci	else
38888c2ecf20Sopenharmony_ci		return hdsp->playback_buffer + (mapped_channel * HDSP_CHANNEL_BUFFER_BYTES);
38898c2ecf20Sopenharmony_ci}
38908c2ecf20Sopenharmony_ci
38918c2ecf20Sopenharmony_cistatic int snd_hdsp_playback_copy(struct snd_pcm_substream *substream,
38928c2ecf20Sopenharmony_ci				  int channel, unsigned long pos,
38938c2ecf20Sopenharmony_ci				  void __user *src, unsigned long count)
38948c2ecf20Sopenharmony_ci{
38958c2ecf20Sopenharmony_ci	struct hdsp *hdsp = snd_pcm_substream_chip(substream);
38968c2ecf20Sopenharmony_ci	signed char *channel_buf;
38978c2ecf20Sopenharmony_ci
38988c2ecf20Sopenharmony_ci	if (snd_BUG_ON(pos + count > HDSP_CHANNEL_BUFFER_BYTES))
38998c2ecf20Sopenharmony_ci		return -EINVAL;
39008c2ecf20Sopenharmony_ci
39018c2ecf20Sopenharmony_ci	channel_buf = hdsp_channel_buffer_location (hdsp, substream->pstr->stream, channel);
39028c2ecf20Sopenharmony_ci	if (snd_BUG_ON(!channel_buf))
39038c2ecf20Sopenharmony_ci		return -EIO;
39048c2ecf20Sopenharmony_ci	if (copy_from_user(channel_buf + pos, src, count))
39058c2ecf20Sopenharmony_ci		return -EFAULT;
39068c2ecf20Sopenharmony_ci	return 0;
39078c2ecf20Sopenharmony_ci}
39088c2ecf20Sopenharmony_ci
39098c2ecf20Sopenharmony_cistatic int snd_hdsp_playback_copy_kernel(struct snd_pcm_substream *substream,
39108c2ecf20Sopenharmony_ci					 int channel, unsigned long pos,
39118c2ecf20Sopenharmony_ci					 void *src, unsigned long count)
39128c2ecf20Sopenharmony_ci{
39138c2ecf20Sopenharmony_ci	struct hdsp *hdsp = snd_pcm_substream_chip(substream);
39148c2ecf20Sopenharmony_ci	signed char *channel_buf;
39158c2ecf20Sopenharmony_ci
39168c2ecf20Sopenharmony_ci	channel_buf = hdsp_channel_buffer_location(hdsp, substream->pstr->stream, channel);
39178c2ecf20Sopenharmony_ci	if (snd_BUG_ON(!channel_buf))
39188c2ecf20Sopenharmony_ci		return -EIO;
39198c2ecf20Sopenharmony_ci	memcpy(channel_buf + pos, src, count);
39208c2ecf20Sopenharmony_ci	return 0;
39218c2ecf20Sopenharmony_ci}
39228c2ecf20Sopenharmony_ci
39238c2ecf20Sopenharmony_cistatic int snd_hdsp_capture_copy(struct snd_pcm_substream *substream,
39248c2ecf20Sopenharmony_ci				 int channel, unsigned long pos,
39258c2ecf20Sopenharmony_ci				 void __user *dst, unsigned long count)
39268c2ecf20Sopenharmony_ci{
39278c2ecf20Sopenharmony_ci	struct hdsp *hdsp = snd_pcm_substream_chip(substream);
39288c2ecf20Sopenharmony_ci	signed char *channel_buf;
39298c2ecf20Sopenharmony_ci
39308c2ecf20Sopenharmony_ci	if (snd_BUG_ON(pos + count > HDSP_CHANNEL_BUFFER_BYTES))
39318c2ecf20Sopenharmony_ci		return -EINVAL;
39328c2ecf20Sopenharmony_ci
39338c2ecf20Sopenharmony_ci	channel_buf = hdsp_channel_buffer_location (hdsp, substream->pstr->stream, channel);
39348c2ecf20Sopenharmony_ci	if (snd_BUG_ON(!channel_buf))
39358c2ecf20Sopenharmony_ci		return -EIO;
39368c2ecf20Sopenharmony_ci	if (copy_to_user(dst, channel_buf + pos, count))
39378c2ecf20Sopenharmony_ci		return -EFAULT;
39388c2ecf20Sopenharmony_ci	return 0;
39398c2ecf20Sopenharmony_ci}
39408c2ecf20Sopenharmony_ci
39418c2ecf20Sopenharmony_cistatic int snd_hdsp_capture_copy_kernel(struct snd_pcm_substream *substream,
39428c2ecf20Sopenharmony_ci					int channel, unsigned long pos,
39438c2ecf20Sopenharmony_ci					void *dst, unsigned long count)
39448c2ecf20Sopenharmony_ci{
39458c2ecf20Sopenharmony_ci	struct hdsp *hdsp = snd_pcm_substream_chip(substream);
39468c2ecf20Sopenharmony_ci	signed char *channel_buf;
39478c2ecf20Sopenharmony_ci
39488c2ecf20Sopenharmony_ci	channel_buf = hdsp_channel_buffer_location(hdsp, substream->pstr->stream, channel);
39498c2ecf20Sopenharmony_ci	if (snd_BUG_ON(!channel_buf))
39508c2ecf20Sopenharmony_ci		return -EIO;
39518c2ecf20Sopenharmony_ci	memcpy(dst, channel_buf + pos, count);
39528c2ecf20Sopenharmony_ci	return 0;
39538c2ecf20Sopenharmony_ci}
39548c2ecf20Sopenharmony_ci
39558c2ecf20Sopenharmony_cistatic int snd_hdsp_hw_silence(struct snd_pcm_substream *substream,
39568c2ecf20Sopenharmony_ci			       int channel, unsigned long pos,
39578c2ecf20Sopenharmony_ci			       unsigned long count)
39588c2ecf20Sopenharmony_ci{
39598c2ecf20Sopenharmony_ci	struct hdsp *hdsp = snd_pcm_substream_chip(substream);
39608c2ecf20Sopenharmony_ci	signed char *channel_buf;
39618c2ecf20Sopenharmony_ci
39628c2ecf20Sopenharmony_ci	channel_buf = hdsp_channel_buffer_location (hdsp, substream->pstr->stream, channel);
39638c2ecf20Sopenharmony_ci	if (snd_BUG_ON(!channel_buf))
39648c2ecf20Sopenharmony_ci		return -EIO;
39658c2ecf20Sopenharmony_ci	memset(channel_buf + pos, 0, count);
39668c2ecf20Sopenharmony_ci	return 0;
39678c2ecf20Sopenharmony_ci}
39688c2ecf20Sopenharmony_ci
39698c2ecf20Sopenharmony_cistatic int snd_hdsp_reset(struct snd_pcm_substream *substream)
39708c2ecf20Sopenharmony_ci{
39718c2ecf20Sopenharmony_ci	struct snd_pcm_runtime *runtime = substream->runtime;
39728c2ecf20Sopenharmony_ci	struct hdsp *hdsp = snd_pcm_substream_chip(substream);
39738c2ecf20Sopenharmony_ci	struct snd_pcm_substream *other;
39748c2ecf20Sopenharmony_ci	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
39758c2ecf20Sopenharmony_ci		other = hdsp->capture_substream;
39768c2ecf20Sopenharmony_ci	else
39778c2ecf20Sopenharmony_ci		other = hdsp->playback_substream;
39788c2ecf20Sopenharmony_ci	if (hdsp->running)
39798c2ecf20Sopenharmony_ci		runtime->status->hw_ptr = hdsp_hw_pointer(hdsp);
39808c2ecf20Sopenharmony_ci	else
39818c2ecf20Sopenharmony_ci		runtime->status->hw_ptr = 0;
39828c2ecf20Sopenharmony_ci	if (other) {
39838c2ecf20Sopenharmony_ci		struct snd_pcm_substream *s;
39848c2ecf20Sopenharmony_ci		struct snd_pcm_runtime *oruntime = other->runtime;
39858c2ecf20Sopenharmony_ci		snd_pcm_group_for_each_entry(s, substream) {
39868c2ecf20Sopenharmony_ci			if (s == other) {
39878c2ecf20Sopenharmony_ci				oruntime->status->hw_ptr = runtime->status->hw_ptr;
39888c2ecf20Sopenharmony_ci				break;
39898c2ecf20Sopenharmony_ci			}
39908c2ecf20Sopenharmony_ci		}
39918c2ecf20Sopenharmony_ci	}
39928c2ecf20Sopenharmony_ci	return 0;
39938c2ecf20Sopenharmony_ci}
39948c2ecf20Sopenharmony_ci
39958c2ecf20Sopenharmony_cistatic int snd_hdsp_hw_params(struct snd_pcm_substream *substream,
39968c2ecf20Sopenharmony_ci				 struct snd_pcm_hw_params *params)
39978c2ecf20Sopenharmony_ci{
39988c2ecf20Sopenharmony_ci	struct hdsp *hdsp = snd_pcm_substream_chip(substream);
39998c2ecf20Sopenharmony_ci	int err;
40008c2ecf20Sopenharmony_ci	pid_t this_pid;
40018c2ecf20Sopenharmony_ci	pid_t other_pid;
40028c2ecf20Sopenharmony_ci
40038c2ecf20Sopenharmony_ci	if (hdsp_check_for_iobox (hdsp))
40048c2ecf20Sopenharmony_ci		return -EIO;
40058c2ecf20Sopenharmony_ci
40068c2ecf20Sopenharmony_ci	if (hdsp_check_for_firmware(hdsp, 1))
40078c2ecf20Sopenharmony_ci		return -EIO;
40088c2ecf20Sopenharmony_ci
40098c2ecf20Sopenharmony_ci	spin_lock_irq(&hdsp->lock);
40108c2ecf20Sopenharmony_ci
40118c2ecf20Sopenharmony_ci	if (substream->pstr->stream == SNDRV_PCM_STREAM_PLAYBACK) {
40128c2ecf20Sopenharmony_ci		hdsp->control_register &= ~(HDSP_SPDIFProfessional | HDSP_SPDIFNonAudio | HDSP_SPDIFEmphasis);
40138c2ecf20Sopenharmony_ci		hdsp_write(hdsp, HDSP_controlRegister, hdsp->control_register |= hdsp->creg_spdif_stream);
40148c2ecf20Sopenharmony_ci		this_pid = hdsp->playback_pid;
40158c2ecf20Sopenharmony_ci		other_pid = hdsp->capture_pid;
40168c2ecf20Sopenharmony_ci	} else {
40178c2ecf20Sopenharmony_ci		this_pid = hdsp->capture_pid;
40188c2ecf20Sopenharmony_ci		other_pid = hdsp->playback_pid;
40198c2ecf20Sopenharmony_ci	}
40208c2ecf20Sopenharmony_ci
40218c2ecf20Sopenharmony_ci	if ((other_pid > 0) && (this_pid != other_pid)) {
40228c2ecf20Sopenharmony_ci
40238c2ecf20Sopenharmony_ci		/* The other stream is open, and not by the same
40248c2ecf20Sopenharmony_ci		   task as this one. Make sure that the parameters
40258c2ecf20Sopenharmony_ci		   that matter are the same.
40268c2ecf20Sopenharmony_ci		 */
40278c2ecf20Sopenharmony_ci
40288c2ecf20Sopenharmony_ci		if (params_rate(params) != hdsp->system_sample_rate) {
40298c2ecf20Sopenharmony_ci			spin_unlock_irq(&hdsp->lock);
40308c2ecf20Sopenharmony_ci			_snd_pcm_hw_param_setempty(params, SNDRV_PCM_HW_PARAM_RATE);
40318c2ecf20Sopenharmony_ci			return -EBUSY;
40328c2ecf20Sopenharmony_ci		}
40338c2ecf20Sopenharmony_ci
40348c2ecf20Sopenharmony_ci		if (params_period_size(params) != hdsp->period_bytes / 4) {
40358c2ecf20Sopenharmony_ci			spin_unlock_irq(&hdsp->lock);
40368c2ecf20Sopenharmony_ci			_snd_pcm_hw_param_setempty(params, SNDRV_PCM_HW_PARAM_PERIOD_SIZE);
40378c2ecf20Sopenharmony_ci			return -EBUSY;
40388c2ecf20Sopenharmony_ci		}
40398c2ecf20Sopenharmony_ci
40408c2ecf20Sopenharmony_ci		/* We're fine. */
40418c2ecf20Sopenharmony_ci
40428c2ecf20Sopenharmony_ci		spin_unlock_irq(&hdsp->lock);
40438c2ecf20Sopenharmony_ci 		return 0;
40448c2ecf20Sopenharmony_ci
40458c2ecf20Sopenharmony_ci	} else {
40468c2ecf20Sopenharmony_ci		spin_unlock_irq(&hdsp->lock);
40478c2ecf20Sopenharmony_ci	}
40488c2ecf20Sopenharmony_ci
40498c2ecf20Sopenharmony_ci	/* how to make sure that the rate matches an externally-set one ?
40508c2ecf20Sopenharmony_ci	 */
40518c2ecf20Sopenharmony_ci
40528c2ecf20Sopenharmony_ci	spin_lock_irq(&hdsp->lock);
40538c2ecf20Sopenharmony_ci	if (! hdsp->clock_source_locked) {
40548c2ecf20Sopenharmony_ci		if ((err = hdsp_set_rate(hdsp, params_rate(params), 0)) < 0) {
40558c2ecf20Sopenharmony_ci			spin_unlock_irq(&hdsp->lock);
40568c2ecf20Sopenharmony_ci			_snd_pcm_hw_param_setempty(params, SNDRV_PCM_HW_PARAM_RATE);
40578c2ecf20Sopenharmony_ci			return err;
40588c2ecf20Sopenharmony_ci		}
40598c2ecf20Sopenharmony_ci	}
40608c2ecf20Sopenharmony_ci	spin_unlock_irq(&hdsp->lock);
40618c2ecf20Sopenharmony_ci
40628c2ecf20Sopenharmony_ci	if ((err = hdsp_set_interrupt_interval(hdsp, params_period_size(params))) < 0) {
40638c2ecf20Sopenharmony_ci		_snd_pcm_hw_param_setempty(params, SNDRV_PCM_HW_PARAM_PERIOD_SIZE);
40648c2ecf20Sopenharmony_ci		return err;
40658c2ecf20Sopenharmony_ci	}
40668c2ecf20Sopenharmony_ci
40678c2ecf20Sopenharmony_ci	return 0;
40688c2ecf20Sopenharmony_ci}
40698c2ecf20Sopenharmony_ci
40708c2ecf20Sopenharmony_cistatic int snd_hdsp_channel_info(struct snd_pcm_substream *substream,
40718c2ecf20Sopenharmony_ci				    struct snd_pcm_channel_info *info)
40728c2ecf20Sopenharmony_ci{
40738c2ecf20Sopenharmony_ci	struct hdsp *hdsp = snd_pcm_substream_chip(substream);
40748c2ecf20Sopenharmony_ci	unsigned int channel = info->channel;
40758c2ecf20Sopenharmony_ci
40768c2ecf20Sopenharmony_ci	if (snd_BUG_ON(channel >= hdsp->max_channels))
40778c2ecf20Sopenharmony_ci		return -EINVAL;
40788c2ecf20Sopenharmony_ci	channel = array_index_nospec(channel, hdsp->max_channels);
40798c2ecf20Sopenharmony_ci
40808c2ecf20Sopenharmony_ci	if (hdsp->channel_map[channel] < 0)
40818c2ecf20Sopenharmony_ci		return -EINVAL;
40828c2ecf20Sopenharmony_ci
40838c2ecf20Sopenharmony_ci	info->offset = hdsp->channel_map[channel] * HDSP_CHANNEL_BUFFER_BYTES;
40848c2ecf20Sopenharmony_ci	info->first = 0;
40858c2ecf20Sopenharmony_ci	info->step = 32;
40868c2ecf20Sopenharmony_ci	return 0;
40878c2ecf20Sopenharmony_ci}
40888c2ecf20Sopenharmony_ci
40898c2ecf20Sopenharmony_cistatic int snd_hdsp_ioctl(struct snd_pcm_substream *substream,
40908c2ecf20Sopenharmony_ci			     unsigned int cmd, void *arg)
40918c2ecf20Sopenharmony_ci{
40928c2ecf20Sopenharmony_ci	switch (cmd) {
40938c2ecf20Sopenharmony_ci	case SNDRV_PCM_IOCTL1_RESET:
40948c2ecf20Sopenharmony_ci		return snd_hdsp_reset(substream);
40958c2ecf20Sopenharmony_ci	case SNDRV_PCM_IOCTL1_CHANNEL_INFO:
40968c2ecf20Sopenharmony_ci		return snd_hdsp_channel_info(substream, arg);
40978c2ecf20Sopenharmony_ci	default:
40988c2ecf20Sopenharmony_ci		break;
40998c2ecf20Sopenharmony_ci	}
41008c2ecf20Sopenharmony_ci
41018c2ecf20Sopenharmony_ci	return snd_pcm_lib_ioctl(substream, cmd, arg);
41028c2ecf20Sopenharmony_ci}
41038c2ecf20Sopenharmony_ci
41048c2ecf20Sopenharmony_cistatic int snd_hdsp_trigger(struct snd_pcm_substream *substream, int cmd)
41058c2ecf20Sopenharmony_ci{
41068c2ecf20Sopenharmony_ci	struct hdsp *hdsp = snd_pcm_substream_chip(substream);
41078c2ecf20Sopenharmony_ci	struct snd_pcm_substream *other;
41088c2ecf20Sopenharmony_ci	int running;
41098c2ecf20Sopenharmony_ci
41108c2ecf20Sopenharmony_ci	if (hdsp_check_for_iobox (hdsp))
41118c2ecf20Sopenharmony_ci		return -EIO;
41128c2ecf20Sopenharmony_ci
41138c2ecf20Sopenharmony_ci	if (hdsp_check_for_firmware(hdsp, 0)) /* no auto-loading in trigger */
41148c2ecf20Sopenharmony_ci		return -EIO;
41158c2ecf20Sopenharmony_ci
41168c2ecf20Sopenharmony_ci	spin_lock(&hdsp->lock);
41178c2ecf20Sopenharmony_ci	running = hdsp->running;
41188c2ecf20Sopenharmony_ci	switch (cmd) {
41198c2ecf20Sopenharmony_ci	case SNDRV_PCM_TRIGGER_START:
41208c2ecf20Sopenharmony_ci		running |= 1 << substream->stream;
41218c2ecf20Sopenharmony_ci		break;
41228c2ecf20Sopenharmony_ci	case SNDRV_PCM_TRIGGER_STOP:
41238c2ecf20Sopenharmony_ci		running &= ~(1 << substream->stream);
41248c2ecf20Sopenharmony_ci		break;
41258c2ecf20Sopenharmony_ci	default:
41268c2ecf20Sopenharmony_ci		snd_BUG();
41278c2ecf20Sopenharmony_ci		spin_unlock(&hdsp->lock);
41288c2ecf20Sopenharmony_ci		return -EINVAL;
41298c2ecf20Sopenharmony_ci	}
41308c2ecf20Sopenharmony_ci	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
41318c2ecf20Sopenharmony_ci		other = hdsp->capture_substream;
41328c2ecf20Sopenharmony_ci	else
41338c2ecf20Sopenharmony_ci		other = hdsp->playback_substream;
41348c2ecf20Sopenharmony_ci
41358c2ecf20Sopenharmony_ci	if (other) {
41368c2ecf20Sopenharmony_ci		struct snd_pcm_substream *s;
41378c2ecf20Sopenharmony_ci		snd_pcm_group_for_each_entry(s, substream) {
41388c2ecf20Sopenharmony_ci			if (s == other) {
41398c2ecf20Sopenharmony_ci				snd_pcm_trigger_done(s, substream);
41408c2ecf20Sopenharmony_ci				if (cmd == SNDRV_PCM_TRIGGER_START)
41418c2ecf20Sopenharmony_ci					running |= 1 << s->stream;
41428c2ecf20Sopenharmony_ci				else
41438c2ecf20Sopenharmony_ci					running &= ~(1 << s->stream);
41448c2ecf20Sopenharmony_ci				goto _ok;
41458c2ecf20Sopenharmony_ci			}
41468c2ecf20Sopenharmony_ci		}
41478c2ecf20Sopenharmony_ci		if (cmd == SNDRV_PCM_TRIGGER_START) {
41488c2ecf20Sopenharmony_ci			if (!(running & (1 << SNDRV_PCM_STREAM_PLAYBACK)) &&
41498c2ecf20Sopenharmony_ci			    substream->stream == SNDRV_PCM_STREAM_CAPTURE)
41508c2ecf20Sopenharmony_ci				hdsp_silence_playback(hdsp);
41518c2ecf20Sopenharmony_ci		} else {
41528c2ecf20Sopenharmony_ci			if (running &&
41538c2ecf20Sopenharmony_ci			    substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
41548c2ecf20Sopenharmony_ci				hdsp_silence_playback(hdsp);
41558c2ecf20Sopenharmony_ci		}
41568c2ecf20Sopenharmony_ci	} else {
41578c2ecf20Sopenharmony_ci		if (substream->stream == SNDRV_PCM_STREAM_CAPTURE)
41588c2ecf20Sopenharmony_ci				hdsp_silence_playback(hdsp);
41598c2ecf20Sopenharmony_ci	}
41608c2ecf20Sopenharmony_ci _ok:
41618c2ecf20Sopenharmony_ci	snd_pcm_trigger_done(substream, substream);
41628c2ecf20Sopenharmony_ci	if (!hdsp->running && running)
41638c2ecf20Sopenharmony_ci		hdsp_start_audio(hdsp);
41648c2ecf20Sopenharmony_ci	else if (hdsp->running && !running)
41658c2ecf20Sopenharmony_ci		hdsp_stop_audio(hdsp);
41668c2ecf20Sopenharmony_ci	hdsp->running = running;
41678c2ecf20Sopenharmony_ci	spin_unlock(&hdsp->lock);
41688c2ecf20Sopenharmony_ci
41698c2ecf20Sopenharmony_ci	return 0;
41708c2ecf20Sopenharmony_ci}
41718c2ecf20Sopenharmony_ci
41728c2ecf20Sopenharmony_cistatic int snd_hdsp_prepare(struct snd_pcm_substream *substream)
41738c2ecf20Sopenharmony_ci{
41748c2ecf20Sopenharmony_ci	struct hdsp *hdsp = snd_pcm_substream_chip(substream);
41758c2ecf20Sopenharmony_ci	int result = 0;
41768c2ecf20Sopenharmony_ci
41778c2ecf20Sopenharmony_ci	if (hdsp_check_for_iobox (hdsp))
41788c2ecf20Sopenharmony_ci		return -EIO;
41798c2ecf20Sopenharmony_ci
41808c2ecf20Sopenharmony_ci	if (hdsp_check_for_firmware(hdsp, 1))
41818c2ecf20Sopenharmony_ci		return -EIO;
41828c2ecf20Sopenharmony_ci
41838c2ecf20Sopenharmony_ci	spin_lock_irq(&hdsp->lock);
41848c2ecf20Sopenharmony_ci	if (!hdsp->running)
41858c2ecf20Sopenharmony_ci		hdsp_reset_hw_pointer(hdsp);
41868c2ecf20Sopenharmony_ci	spin_unlock_irq(&hdsp->lock);
41878c2ecf20Sopenharmony_ci	return result;
41888c2ecf20Sopenharmony_ci}
41898c2ecf20Sopenharmony_ci
41908c2ecf20Sopenharmony_cistatic const struct snd_pcm_hardware snd_hdsp_playback_subinfo =
41918c2ecf20Sopenharmony_ci{
41928c2ecf20Sopenharmony_ci	.info =			(SNDRV_PCM_INFO_MMAP |
41938c2ecf20Sopenharmony_ci				 SNDRV_PCM_INFO_MMAP_VALID |
41948c2ecf20Sopenharmony_ci				 SNDRV_PCM_INFO_NONINTERLEAVED |
41958c2ecf20Sopenharmony_ci				 SNDRV_PCM_INFO_SYNC_START |
41968c2ecf20Sopenharmony_ci				 SNDRV_PCM_INFO_DOUBLE),
41978c2ecf20Sopenharmony_ci#ifdef SNDRV_BIG_ENDIAN
41988c2ecf20Sopenharmony_ci	.formats =		SNDRV_PCM_FMTBIT_S32_BE,
41998c2ecf20Sopenharmony_ci#else
42008c2ecf20Sopenharmony_ci	.formats =		SNDRV_PCM_FMTBIT_S32_LE,
42018c2ecf20Sopenharmony_ci#endif
42028c2ecf20Sopenharmony_ci	.rates =		(SNDRV_PCM_RATE_32000 |
42038c2ecf20Sopenharmony_ci				 SNDRV_PCM_RATE_44100 |
42048c2ecf20Sopenharmony_ci				 SNDRV_PCM_RATE_48000 |
42058c2ecf20Sopenharmony_ci				 SNDRV_PCM_RATE_64000 |
42068c2ecf20Sopenharmony_ci				 SNDRV_PCM_RATE_88200 |
42078c2ecf20Sopenharmony_ci				 SNDRV_PCM_RATE_96000),
42088c2ecf20Sopenharmony_ci	.rate_min =		32000,
42098c2ecf20Sopenharmony_ci	.rate_max =		96000,
42108c2ecf20Sopenharmony_ci	.channels_min =		6,
42118c2ecf20Sopenharmony_ci	.channels_max =		HDSP_MAX_CHANNELS,
42128c2ecf20Sopenharmony_ci	.buffer_bytes_max =	HDSP_CHANNEL_BUFFER_BYTES * HDSP_MAX_CHANNELS,
42138c2ecf20Sopenharmony_ci	.period_bytes_min =	(64 * 4) * 10,
42148c2ecf20Sopenharmony_ci	.period_bytes_max =	(8192 * 4) * HDSP_MAX_CHANNELS,
42158c2ecf20Sopenharmony_ci	.periods_min =		2,
42168c2ecf20Sopenharmony_ci	.periods_max =		2,
42178c2ecf20Sopenharmony_ci	.fifo_size =		0
42188c2ecf20Sopenharmony_ci};
42198c2ecf20Sopenharmony_ci
42208c2ecf20Sopenharmony_cistatic const struct snd_pcm_hardware snd_hdsp_capture_subinfo =
42218c2ecf20Sopenharmony_ci{
42228c2ecf20Sopenharmony_ci	.info =			(SNDRV_PCM_INFO_MMAP |
42238c2ecf20Sopenharmony_ci				 SNDRV_PCM_INFO_MMAP_VALID |
42248c2ecf20Sopenharmony_ci				 SNDRV_PCM_INFO_NONINTERLEAVED |
42258c2ecf20Sopenharmony_ci				 SNDRV_PCM_INFO_SYNC_START),
42268c2ecf20Sopenharmony_ci#ifdef SNDRV_BIG_ENDIAN
42278c2ecf20Sopenharmony_ci	.formats =		SNDRV_PCM_FMTBIT_S32_BE,
42288c2ecf20Sopenharmony_ci#else
42298c2ecf20Sopenharmony_ci	.formats =		SNDRV_PCM_FMTBIT_S32_LE,
42308c2ecf20Sopenharmony_ci#endif
42318c2ecf20Sopenharmony_ci	.rates =		(SNDRV_PCM_RATE_32000 |
42328c2ecf20Sopenharmony_ci				 SNDRV_PCM_RATE_44100 |
42338c2ecf20Sopenharmony_ci				 SNDRV_PCM_RATE_48000 |
42348c2ecf20Sopenharmony_ci				 SNDRV_PCM_RATE_64000 |
42358c2ecf20Sopenharmony_ci				 SNDRV_PCM_RATE_88200 |
42368c2ecf20Sopenharmony_ci				 SNDRV_PCM_RATE_96000),
42378c2ecf20Sopenharmony_ci	.rate_min =		32000,
42388c2ecf20Sopenharmony_ci	.rate_max =		96000,
42398c2ecf20Sopenharmony_ci	.channels_min =		5,
42408c2ecf20Sopenharmony_ci	.channels_max =		HDSP_MAX_CHANNELS,
42418c2ecf20Sopenharmony_ci	.buffer_bytes_max =	HDSP_CHANNEL_BUFFER_BYTES * HDSP_MAX_CHANNELS,
42428c2ecf20Sopenharmony_ci	.period_bytes_min =	(64 * 4) * 10,
42438c2ecf20Sopenharmony_ci	.period_bytes_max =	(8192 * 4) * HDSP_MAX_CHANNELS,
42448c2ecf20Sopenharmony_ci	.periods_min =		2,
42458c2ecf20Sopenharmony_ci	.periods_max =		2,
42468c2ecf20Sopenharmony_ci	.fifo_size =		0
42478c2ecf20Sopenharmony_ci};
42488c2ecf20Sopenharmony_ci
42498c2ecf20Sopenharmony_cistatic const unsigned int hdsp_period_sizes[] = { 64, 128, 256, 512, 1024, 2048, 4096, 8192 };
42508c2ecf20Sopenharmony_ci
42518c2ecf20Sopenharmony_cistatic const struct snd_pcm_hw_constraint_list hdsp_hw_constraints_period_sizes = {
42528c2ecf20Sopenharmony_ci	.count = ARRAY_SIZE(hdsp_period_sizes),
42538c2ecf20Sopenharmony_ci	.list = hdsp_period_sizes,
42548c2ecf20Sopenharmony_ci	.mask = 0
42558c2ecf20Sopenharmony_ci};
42568c2ecf20Sopenharmony_ci
42578c2ecf20Sopenharmony_cistatic const unsigned int hdsp_9632_sample_rates[] = { 32000, 44100, 48000, 64000, 88200, 96000, 128000, 176400, 192000 };
42588c2ecf20Sopenharmony_ci
42598c2ecf20Sopenharmony_cistatic const struct snd_pcm_hw_constraint_list hdsp_hw_constraints_9632_sample_rates = {
42608c2ecf20Sopenharmony_ci	.count = ARRAY_SIZE(hdsp_9632_sample_rates),
42618c2ecf20Sopenharmony_ci	.list = hdsp_9632_sample_rates,
42628c2ecf20Sopenharmony_ci	.mask = 0
42638c2ecf20Sopenharmony_ci};
42648c2ecf20Sopenharmony_ci
42658c2ecf20Sopenharmony_cistatic int snd_hdsp_hw_rule_in_channels(struct snd_pcm_hw_params *params,
42668c2ecf20Sopenharmony_ci					struct snd_pcm_hw_rule *rule)
42678c2ecf20Sopenharmony_ci{
42688c2ecf20Sopenharmony_ci	struct hdsp *hdsp = rule->private;
42698c2ecf20Sopenharmony_ci	struct snd_interval *c = hw_param_interval(params, SNDRV_PCM_HW_PARAM_CHANNELS);
42708c2ecf20Sopenharmony_ci	if (hdsp->io_type == H9632) {
42718c2ecf20Sopenharmony_ci		unsigned int list[3];
42728c2ecf20Sopenharmony_ci		list[0] = hdsp->qs_in_channels;
42738c2ecf20Sopenharmony_ci		list[1] = hdsp->ds_in_channels;
42748c2ecf20Sopenharmony_ci		list[2] = hdsp->ss_in_channels;
42758c2ecf20Sopenharmony_ci		return snd_interval_list(c, 3, list, 0);
42768c2ecf20Sopenharmony_ci	} else {
42778c2ecf20Sopenharmony_ci		unsigned int list[2];
42788c2ecf20Sopenharmony_ci		list[0] = hdsp->ds_in_channels;
42798c2ecf20Sopenharmony_ci		list[1] = hdsp->ss_in_channels;
42808c2ecf20Sopenharmony_ci		return snd_interval_list(c, 2, list, 0);
42818c2ecf20Sopenharmony_ci	}
42828c2ecf20Sopenharmony_ci}
42838c2ecf20Sopenharmony_ci
42848c2ecf20Sopenharmony_cistatic int snd_hdsp_hw_rule_out_channels(struct snd_pcm_hw_params *params,
42858c2ecf20Sopenharmony_ci					struct snd_pcm_hw_rule *rule)
42868c2ecf20Sopenharmony_ci{
42878c2ecf20Sopenharmony_ci	unsigned int list[3];
42888c2ecf20Sopenharmony_ci	struct hdsp *hdsp = rule->private;
42898c2ecf20Sopenharmony_ci	struct snd_interval *c = hw_param_interval(params, SNDRV_PCM_HW_PARAM_CHANNELS);
42908c2ecf20Sopenharmony_ci	if (hdsp->io_type == H9632) {
42918c2ecf20Sopenharmony_ci		list[0] = hdsp->qs_out_channels;
42928c2ecf20Sopenharmony_ci		list[1] = hdsp->ds_out_channels;
42938c2ecf20Sopenharmony_ci		list[2] = hdsp->ss_out_channels;
42948c2ecf20Sopenharmony_ci		return snd_interval_list(c, 3, list, 0);
42958c2ecf20Sopenharmony_ci	} else {
42968c2ecf20Sopenharmony_ci		list[0] = hdsp->ds_out_channels;
42978c2ecf20Sopenharmony_ci		list[1] = hdsp->ss_out_channels;
42988c2ecf20Sopenharmony_ci	}
42998c2ecf20Sopenharmony_ci	return snd_interval_list(c, 2, list, 0);
43008c2ecf20Sopenharmony_ci}
43018c2ecf20Sopenharmony_ci
43028c2ecf20Sopenharmony_cistatic int snd_hdsp_hw_rule_in_channels_rate(struct snd_pcm_hw_params *params,
43038c2ecf20Sopenharmony_ci					     struct snd_pcm_hw_rule *rule)
43048c2ecf20Sopenharmony_ci{
43058c2ecf20Sopenharmony_ci	struct hdsp *hdsp = rule->private;
43068c2ecf20Sopenharmony_ci	struct snd_interval *c = hw_param_interval(params, SNDRV_PCM_HW_PARAM_CHANNELS);
43078c2ecf20Sopenharmony_ci	struct snd_interval *r = hw_param_interval(params, SNDRV_PCM_HW_PARAM_RATE);
43088c2ecf20Sopenharmony_ci	if (r->min > 96000 && hdsp->io_type == H9632) {
43098c2ecf20Sopenharmony_ci		struct snd_interval t = {
43108c2ecf20Sopenharmony_ci			.min = hdsp->qs_in_channels,
43118c2ecf20Sopenharmony_ci			.max = hdsp->qs_in_channels,
43128c2ecf20Sopenharmony_ci			.integer = 1,
43138c2ecf20Sopenharmony_ci		};
43148c2ecf20Sopenharmony_ci		return snd_interval_refine(c, &t);
43158c2ecf20Sopenharmony_ci	} else if (r->min > 48000 && r->max <= 96000) {
43168c2ecf20Sopenharmony_ci		struct snd_interval t = {
43178c2ecf20Sopenharmony_ci			.min = hdsp->ds_in_channels,
43188c2ecf20Sopenharmony_ci			.max = hdsp->ds_in_channels,
43198c2ecf20Sopenharmony_ci			.integer = 1,
43208c2ecf20Sopenharmony_ci		};
43218c2ecf20Sopenharmony_ci		return snd_interval_refine(c, &t);
43228c2ecf20Sopenharmony_ci	} else if (r->max < 64000) {
43238c2ecf20Sopenharmony_ci		struct snd_interval t = {
43248c2ecf20Sopenharmony_ci			.min = hdsp->ss_in_channels,
43258c2ecf20Sopenharmony_ci			.max = hdsp->ss_in_channels,
43268c2ecf20Sopenharmony_ci			.integer = 1,
43278c2ecf20Sopenharmony_ci		};
43288c2ecf20Sopenharmony_ci		return snd_interval_refine(c, &t);
43298c2ecf20Sopenharmony_ci	}
43308c2ecf20Sopenharmony_ci	return 0;
43318c2ecf20Sopenharmony_ci}
43328c2ecf20Sopenharmony_ci
43338c2ecf20Sopenharmony_cistatic int snd_hdsp_hw_rule_out_channels_rate(struct snd_pcm_hw_params *params,
43348c2ecf20Sopenharmony_ci					     struct snd_pcm_hw_rule *rule)
43358c2ecf20Sopenharmony_ci{
43368c2ecf20Sopenharmony_ci	struct hdsp *hdsp = rule->private;
43378c2ecf20Sopenharmony_ci	struct snd_interval *c = hw_param_interval(params, SNDRV_PCM_HW_PARAM_CHANNELS);
43388c2ecf20Sopenharmony_ci	struct snd_interval *r = hw_param_interval(params, SNDRV_PCM_HW_PARAM_RATE);
43398c2ecf20Sopenharmony_ci	if (r->min > 96000 && hdsp->io_type == H9632) {
43408c2ecf20Sopenharmony_ci		struct snd_interval t = {
43418c2ecf20Sopenharmony_ci			.min = hdsp->qs_out_channels,
43428c2ecf20Sopenharmony_ci			.max = hdsp->qs_out_channels,
43438c2ecf20Sopenharmony_ci			.integer = 1,
43448c2ecf20Sopenharmony_ci		};
43458c2ecf20Sopenharmony_ci		return snd_interval_refine(c, &t);
43468c2ecf20Sopenharmony_ci	} else if (r->min > 48000 && r->max <= 96000) {
43478c2ecf20Sopenharmony_ci		struct snd_interval t = {
43488c2ecf20Sopenharmony_ci			.min = hdsp->ds_out_channels,
43498c2ecf20Sopenharmony_ci			.max = hdsp->ds_out_channels,
43508c2ecf20Sopenharmony_ci			.integer = 1,
43518c2ecf20Sopenharmony_ci		};
43528c2ecf20Sopenharmony_ci		return snd_interval_refine(c, &t);
43538c2ecf20Sopenharmony_ci	} else if (r->max < 64000) {
43548c2ecf20Sopenharmony_ci		struct snd_interval t = {
43558c2ecf20Sopenharmony_ci			.min = hdsp->ss_out_channels,
43568c2ecf20Sopenharmony_ci			.max = hdsp->ss_out_channels,
43578c2ecf20Sopenharmony_ci			.integer = 1,
43588c2ecf20Sopenharmony_ci		};
43598c2ecf20Sopenharmony_ci		return snd_interval_refine(c, &t);
43608c2ecf20Sopenharmony_ci	}
43618c2ecf20Sopenharmony_ci	return 0;
43628c2ecf20Sopenharmony_ci}
43638c2ecf20Sopenharmony_ci
43648c2ecf20Sopenharmony_cistatic int snd_hdsp_hw_rule_rate_out_channels(struct snd_pcm_hw_params *params,
43658c2ecf20Sopenharmony_ci					     struct snd_pcm_hw_rule *rule)
43668c2ecf20Sopenharmony_ci{
43678c2ecf20Sopenharmony_ci	struct hdsp *hdsp = rule->private;
43688c2ecf20Sopenharmony_ci	struct snd_interval *c = hw_param_interval(params, SNDRV_PCM_HW_PARAM_CHANNELS);
43698c2ecf20Sopenharmony_ci	struct snd_interval *r = hw_param_interval(params, SNDRV_PCM_HW_PARAM_RATE);
43708c2ecf20Sopenharmony_ci	if (c->min >= hdsp->ss_out_channels) {
43718c2ecf20Sopenharmony_ci		struct snd_interval t = {
43728c2ecf20Sopenharmony_ci			.min = 32000,
43738c2ecf20Sopenharmony_ci			.max = 48000,
43748c2ecf20Sopenharmony_ci			.integer = 1,
43758c2ecf20Sopenharmony_ci		};
43768c2ecf20Sopenharmony_ci		return snd_interval_refine(r, &t);
43778c2ecf20Sopenharmony_ci	} else if (c->max <= hdsp->qs_out_channels && hdsp->io_type == H9632) {
43788c2ecf20Sopenharmony_ci		struct snd_interval t = {
43798c2ecf20Sopenharmony_ci			.min = 128000,
43808c2ecf20Sopenharmony_ci			.max = 192000,
43818c2ecf20Sopenharmony_ci			.integer = 1,
43828c2ecf20Sopenharmony_ci		};
43838c2ecf20Sopenharmony_ci		return snd_interval_refine(r, &t);
43848c2ecf20Sopenharmony_ci	} else if (c->max <= hdsp->ds_out_channels) {
43858c2ecf20Sopenharmony_ci		struct snd_interval t = {
43868c2ecf20Sopenharmony_ci			.min = 64000,
43878c2ecf20Sopenharmony_ci			.max = 96000,
43888c2ecf20Sopenharmony_ci			.integer = 1,
43898c2ecf20Sopenharmony_ci		};
43908c2ecf20Sopenharmony_ci		return snd_interval_refine(r, &t);
43918c2ecf20Sopenharmony_ci	}
43928c2ecf20Sopenharmony_ci	return 0;
43938c2ecf20Sopenharmony_ci}
43948c2ecf20Sopenharmony_ci
43958c2ecf20Sopenharmony_cistatic int snd_hdsp_hw_rule_rate_in_channels(struct snd_pcm_hw_params *params,
43968c2ecf20Sopenharmony_ci					     struct snd_pcm_hw_rule *rule)
43978c2ecf20Sopenharmony_ci{
43988c2ecf20Sopenharmony_ci	struct hdsp *hdsp = rule->private;
43998c2ecf20Sopenharmony_ci	struct snd_interval *c = hw_param_interval(params, SNDRV_PCM_HW_PARAM_CHANNELS);
44008c2ecf20Sopenharmony_ci	struct snd_interval *r = hw_param_interval(params, SNDRV_PCM_HW_PARAM_RATE);
44018c2ecf20Sopenharmony_ci	if (c->min >= hdsp->ss_in_channels) {
44028c2ecf20Sopenharmony_ci		struct snd_interval t = {
44038c2ecf20Sopenharmony_ci			.min = 32000,
44048c2ecf20Sopenharmony_ci			.max = 48000,
44058c2ecf20Sopenharmony_ci			.integer = 1,
44068c2ecf20Sopenharmony_ci		};
44078c2ecf20Sopenharmony_ci		return snd_interval_refine(r, &t);
44088c2ecf20Sopenharmony_ci	} else if (c->max <= hdsp->qs_in_channels && hdsp->io_type == H9632) {
44098c2ecf20Sopenharmony_ci		struct snd_interval t = {
44108c2ecf20Sopenharmony_ci			.min = 128000,
44118c2ecf20Sopenharmony_ci			.max = 192000,
44128c2ecf20Sopenharmony_ci			.integer = 1,
44138c2ecf20Sopenharmony_ci		};
44148c2ecf20Sopenharmony_ci		return snd_interval_refine(r, &t);
44158c2ecf20Sopenharmony_ci	} else if (c->max <= hdsp->ds_in_channels) {
44168c2ecf20Sopenharmony_ci		struct snd_interval t = {
44178c2ecf20Sopenharmony_ci			.min = 64000,
44188c2ecf20Sopenharmony_ci			.max = 96000,
44198c2ecf20Sopenharmony_ci			.integer = 1,
44208c2ecf20Sopenharmony_ci		};
44218c2ecf20Sopenharmony_ci		return snd_interval_refine(r, &t);
44228c2ecf20Sopenharmony_ci	}
44238c2ecf20Sopenharmony_ci	return 0;
44248c2ecf20Sopenharmony_ci}
44258c2ecf20Sopenharmony_ci
44268c2ecf20Sopenharmony_cistatic int snd_hdsp_playback_open(struct snd_pcm_substream *substream)
44278c2ecf20Sopenharmony_ci{
44288c2ecf20Sopenharmony_ci	struct hdsp *hdsp = snd_pcm_substream_chip(substream);
44298c2ecf20Sopenharmony_ci	struct snd_pcm_runtime *runtime = substream->runtime;
44308c2ecf20Sopenharmony_ci
44318c2ecf20Sopenharmony_ci	if (hdsp_check_for_iobox (hdsp))
44328c2ecf20Sopenharmony_ci		return -EIO;
44338c2ecf20Sopenharmony_ci
44348c2ecf20Sopenharmony_ci	if (hdsp_check_for_firmware(hdsp, 1))
44358c2ecf20Sopenharmony_ci		return -EIO;
44368c2ecf20Sopenharmony_ci
44378c2ecf20Sopenharmony_ci	spin_lock_irq(&hdsp->lock);
44388c2ecf20Sopenharmony_ci
44398c2ecf20Sopenharmony_ci	snd_pcm_set_sync(substream);
44408c2ecf20Sopenharmony_ci
44418c2ecf20Sopenharmony_ci        runtime->hw = snd_hdsp_playback_subinfo;
44428c2ecf20Sopenharmony_ci	runtime->dma_area = hdsp->playback_buffer;
44438c2ecf20Sopenharmony_ci	runtime->dma_bytes = HDSP_DMA_AREA_BYTES;
44448c2ecf20Sopenharmony_ci
44458c2ecf20Sopenharmony_ci	hdsp->playback_pid = current->pid;
44468c2ecf20Sopenharmony_ci	hdsp->playback_substream = substream;
44478c2ecf20Sopenharmony_ci
44488c2ecf20Sopenharmony_ci	spin_unlock_irq(&hdsp->lock);
44498c2ecf20Sopenharmony_ci
44508c2ecf20Sopenharmony_ci	snd_pcm_hw_constraint_msbits(runtime, 0, 32, 24);
44518c2ecf20Sopenharmony_ci	snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_PERIOD_SIZE, &hdsp_hw_constraints_period_sizes);
44528c2ecf20Sopenharmony_ci	if (hdsp->clock_source_locked) {
44538c2ecf20Sopenharmony_ci		runtime->hw.rate_min = runtime->hw.rate_max = hdsp->system_sample_rate;
44548c2ecf20Sopenharmony_ci	} else if (hdsp->io_type == H9632) {
44558c2ecf20Sopenharmony_ci		runtime->hw.rate_max = 192000;
44568c2ecf20Sopenharmony_ci		runtime->hw.rates = SNDRV_PCM_RATE_KNOT;
44578c2ecf20Sopenharmony_ci		snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_RATE, &hdsp_hw_constraints_9632_sample_rates);
44588c2ecf20Sopenharmony_ci	}
44598c2ecf20Sopenharmony_ci	if (hdsp->io_type == H9632) {
44608c2ecf20Sopenharmony_ci		runtime->hw.channels_min = hdsp->qs_out_channels;
44618c2ecf20Sopenharmony_ci		runtime->hw.channels_max = hdsp->ss_out_channels;
44628c2ecf20Sopenharmony_ci	}
44638c2ecf20Sopenharmony_ci
44648c2ecf20Sopenharmony_ci	snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_CHANNELS,
44658c2ecf20Sopenharmony_ci			     snd_hdsp_hw_rule_out_channels, hdsp,
44668c2ecf20Sopenharmony_ci			     SNDRV_PCM_HW_PARAM_CHANNELS, -1);
44678c2ecf20Sopenharmony_ci	snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_CHANNELS,
44688c2ecf20Sopenharmony_ci			     snd_hdsp_hw_rule_out_channels_rate, hdsp,
44698c2ecf20Sopenharmony_ci			     SNDRV_PCM_HW_PARAM_RATE, -1);
44708c2ecf20Sopenharmony_ci	snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_RATE,
44718c2ecf20Sopenharmony_ci			     snd_hdsp_hw_rule_rate_out_channels, hdsp,
44728c2ecf20Sopenharmony_ci			     SNDRV_PCM_HW_PARAM_CHANNELS, -1);
44738c2ecf20Sopenharmony_ci
44748c2ecf20Sopenharmony_ci	if (RPM != hdsp->io_type) {
44758c2ecf20Sopenharmony_ci		hdsp->creg_spdif_stream = hdsp->creg_spdif;
44768c2ecf20Sopenharmony_ci		hdsp->spdif_ctl->vd[0].access &= ~SNDRV_CTL_ELEM_ACCESS_INACTIVE;
44778c2ecf20Sopenharmony_ci		snd_ctl_notify(hdsp->card, SNDRV_CTL_EVENT_MASK_VALUE |
44788c2ecf20Sopenharmony_ci			SNDRV_CTL_EVENT_MASK_INFO, &hdsp->spdif_ctl->id);
44798c2ecf20Sopenharmony_ci	}
44808c2ecf20Sopenharmony_ci	return 0;
44818c2ecf20Sopenharmony_ci}
44828c2ecf20Sopenharmony_ci
44838c2ecf20Sopenharmony_cistatic int snd_hdsp_playback_release(struct snd_pcm_substream *substream)
44848c2ecf20Sopenharmony_ci{
44858c2ecf20Sopenharmony_ci	struct hdsp *hdsp = snd_pcm_substream_chip(substream);
44868c2ecf20Sopenharmony_ci
44878c2ecf20Sopenharmony_ci	spin_lock_irq(&hdsp->lock);
44888c2ecf20Sopenharmony_ci
44898c2ecf20Sopenharmony_ci	hdsp->playback_pid = -1;
44908c2ecf20Sopenharmony_ci	hdsp->playback_substream = NULL;
44918c2ecf20Sopenharmony_ci
44928c2ecf20Sopenharmony_ci	spin_unlock_irq(&hdsp->lock);
44938c2ecf20Sopenharmony_ci
44948c2ecf20Sopenharmony_ci	if (RPM != hdsp->io_type) {
44958c2ecf20Sopenharmony_ci		hdsp->spdif_ctl->vd[0].access |= SNDRV_CTL_ELEM_ACCESS_INACTIVE;
44968c2ecf20Sopenharmony_ci		snd_ctl_notify(hdsp->card, SNDRV_CTL_EVENT_MASK_VALUE |
44978c2ecf20Sopenharmony_ci			SNDRV_CTL_EVENT_MASK_INFO, &hdsp->spdif_ctl->id);
44988c2ecf20Sopenharmony_ci	}
44998c2ecf20Sopenharmony_ci	return 0;
45008c2ecf20Sopenharmony_ci}
45018c2ecf20Sopenharmony_ci
45028c2ecf20Sopenharmony_ci
45038c2ecf20Sopenharmony_cistatic int snd_hdsp_capture_open(struct snd_pcm_substream *substream)
45048c2ecf20Sopenharmony_ci{
45058c2ecf20Sopenharmony_ci	struct hdsp *hdsp = snd_pcm_substream_chip(substream);
45068c2ecf20Sopenharmony_ci	struct snd_pcm_runtime *runtime = substream->runtime;
45078c2ecf20Sopenharmony_ci
45088c2ecf20Sopenharmony_ci	if (hdsp_check_for_iobox (hdsp))
45098c2ecf20Sopenharmony_ci		return -EIO;
45108c2ecf20Sopenharmony_ci
45118c2ecf20Sopenharmony_ci	if (hdsp_check_for_firmware(hdsp, 1))
45128c2ecf20Sopenharmony_ci		return -EIO;
45138c2ecf20Sopenharmony_ci
45148c2ecf20Sopenharmony_ci	spin_lock_irq(&hdsp->lock);
45158c2ecf20Sopenharmony_ci
45168c2ecf20Sopenharmony_ci	snd_pcm_set_sync(substream);
45178c2ecf20Sopenharmony_ci
45188c2ecf20Sopenharmony_ci	runtime->hw = snd_hdsp_capture_subinfo;
45198c2ecf20Sopenharmony_ci	runtime->dma_area = hdsp->capture_buffer;
45208c2ecf20Sopenharmony_ci	runtime->dma_bytes = HDSP_DMA_AREA_BYTES;
45218c2ecf20Sopenharmony_ci
45228c2ecf20Sopenharmony_ci	hdsp->capture_pid = current->pid;
45238c2ecf20Sopenharmony_ci	hdsp->capture_substream = substream;
45248c2ecf20Sopenharmony_ci
45258c2ecf20Sopenharmony_ci	spin_unlock_irq(&hdsp->lock);
45268c2ecf20Sopenharmony_ci
45278c2ecf20Sopenharmony_ci	snd_pcm_hw_constraint_msbits(runtime, 0, 32, 24);
45288c2ecf20Sopenharmony_ci	snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_PERIOD_SIZE, &hdsp_hw_constraints_period_sizes);
45298c2ecf20Sopenharmony_ci	if (hdsp->io_type == H9632) {
45308c2ecf20Sopenharmony_ci		runtime->hw.channels_min = hdsp->qs_in_channels;
45318c2ecf20Sopenharmony_ci		runtime->hw.channels_max = hdsp->ss_in_channels;
45328c2ecf20Sopenharmony_ci		runtime->hw.rate_max = 192000;
45338c2ecf20Sopenharmony_ci		runtime->hw.rates = SNDRV_PCM_RATE_KNOT;
45348c2ecf20Sopenharmony_ci		snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_RATE, &hdsp_hw_constraints_9632_sample_rates);
45358c2ecf20Sopenharmony_ci	}
45368c2ecf20Sopenharmony_ci	snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_CHANNELS,
45378c2ecf20Sopenharmony_ci			     snd_hdsp_hw_rule_in_channels, hdsp,
45388c2ecf20Sopenharmony_ci			     SNDRV_PCM_HW_PARAM_CHANNELS, -1);
45398c2ecf20Sopenharmony_ci	snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_CHANNELS,
45408c2ecf20Sopenharmony_ci			     snd_hdsp_hw_rule_in_channels_rate, hdsp,
45418c2ecf20Sopenharmony_ci			     SNDRV_PCM_HW_PARAM_RATE, -1);
45428c2ecf20Sopenharmony_ci	snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_RATE,
45438c2ecf20Sopenharmony_ci			     snd_hdsp_hw_rule_rate_in_channels, hdsp,
45448c2ecf20Sopenharmony_ci			     SNDRV_PCM_HW_PARAM_CHANNELS, -1);
45458c2ecf20Sopenharmony_ci	return 0;
45468c2ecf20Sopenharmony_ci}
45478c2ecf20Sopenharmony_ci
45488c2ecf20Sopenharmony_cistatic int snd_hdsp_capture_release(struct snd_pcm_substream *substream)
45498c2ecf20Sopenharmony_ci{
45508c2ecf20Sopenharmony_ci	struct hdsp *hdsp = snd_pcm_substream_chip(substream);
45518c2ecf20Sopenharmony_ci
45528c2ecf20Sopenharmony_ci	spin_lock_irq(&hdsp->lock);
45538c2ecf20Sopenharmony_ci
45548c2ecf20Sopenharmony_ci	hdsp->capture_pid = -1;
45558c2ecf20Sopenharmony_ci	hdsp->capture_substream = NULL;
45568c2ecf20Sopenharmony_ci
45578c2ecf20Sopenharmony_ci	spin_unlock_irq(&hdsp->lock);
45588c2ecf20Sopenharmony_ci	return 0;
45598c2ecf20Sopenharmony_ci}
45608c2ecf20Sopenharmony_ci
45618c2ecf20Sopenharmony_ci/* helper functions for copying meter values */
45628c2ecf20Sopenharmony_cistatic inline int copy_u32_le(void __user *dest, void __iomem *src)
45638c2ecf20Sopenharmony_ci{
45648c2ecf20Sopenharmony_ci	u32 val = readl(src);
45658c2ecf20Sopenharmony_ci	return copy_to_user(dest, &val, 4);
45668c2ecf20Sopenharmony_ci}
45678c2ecf20Sopenharmony_ci
45688c2ecf20Sopenharmony_cistatic inline int copy_u64_le(void __user *dest, void __iomem *src_low, void __iomem *src_high)
45698c2ecf20Sopenharmony_ci{
45708c2ecf20Sopenharmony_ci	u32 rms_low, rms_high;
45718c2ecf20Sopenharmony_ci	u64 rms;
45728c2ecf20Sopenharmony_ci	rms_low = readl(src_low);
45738c2ecf20Sopenharmony_ci	rms_high = readl(src_high);
45748c2ecf20Sopenharmony_ci	rms = ((u64)rms_high << 32) | rms_low;
45758c2ecf20Sopenharmony_ci	return copy_to_user(dest, &rms, 8);
45768c2ecf20Sopenharmony_ci}
45778c2ecf20Sopenharmony_ci
45788c2ecf20Sopenharmony_cistatic inline int copy_u48_le(void __user *dest, void __iomem *src_low, void __iomem *src_high)
45798c2ecf20Sopenharmony_ci{
45808c2ecf20Sopenharmony_ci	u32 rms_low, rms_high;
45818c2ecf20Sopenharmony_ci	u64 rms;
45828c2ecf20Sopenharmony_ci	rms_low = readl(src_low) & 0xffffff00;
45838c2ecf20Sopenharmony_ci	rms_high = readl(src_high) & 0xffffff00;
45848c2ecf20Sopenharmony_ci	rms = ((u64)rms_high << 32) | rms_low;
45858c2ecf20Sopenharmony_ci	return copy_to_user(dest, &rms, 8);
45868c2ecf20Sopenharmony_ci}
45878c2ecf20Sopenharmony_ci
45888c2ecf20Sopenharmony_cistatic int hdsp_9652_get_peak(struct hdsp *hdsp, struct hdsp_peak_rms __user *peak_rms)
45898c2ecf20Sopenharmony_ci{
45908c2ecf20Sopenharmony_ci	int doublespeed = 0;
45918c2ecf20Sopenharmony_ci	int i, j, channels, ofs;
45928c2ecf20Sopenharmony_ci
45938c2ecf20Sopenharmony_ci	if (hdsp_read (hdsp, HDSP_statusRegister) & HDSP_DoubleSpeedStatus)
45948c2ecf20Sopenharmony_ci		doublespeed = 1;
45958c2ecf20Sopenharmony_ci	channels = doublespeed ? 14 : 26;
45968c2ecf20Sopenharmony_ci	for (i = 0, j = 0; i < 26; ++i) {
45978c2ecf20Sopenharmony_ci		if (doublespeed && (i & 4))
45988c2ecf20Sopenharmony_ci			continue;
45998c2ecf20Sopenharmony_ci		ofs = HDSP_9652_peakBase - j * 4;
46008c2ecf20Sopenharmony_ci		if (copy_u32_le(&peak_rms->input_peaks[i], hdsp->iobase + ofs))
46018c2ecf20Sopenharmony_ci			return -EFAULT;
46028c2ecf20Sopenharmony_ci		ofs -= channels * 4;
46038c2ecf20Sopenharmony_ci		if (copy_u32_le(&peak_rms->playback_peaks[i], hdsp->iobase + ofs))
46048c2ecf20Sopenharmony_ci			return -EFAULT;
46058c2ecf20Sopenharmony_ci		ofs -= channels * 4;
46068c2ecf20Sopenharmony_ci		if (copy_u32_le(&peak_rms->output_peaks[i], hdsp->iobase + ofs))
46078c2ecf20Sopenharmony_ci			return -EFAULT;
46088c2ecf20Sopenharmony_ci		ofs = HDSP_9652_rmsBase + j * 8;
46098c2ecf20Sopenharmony_ci		if (copy_u48_le(&peak_rms->input_rms[i], hdsp->iobase + ofs,
46108c2ecf20Sopenharmony_ci				hdsp->iobase + ofs + 4))
46118c2ecf20Sopenharmony_ci			return -EFAULT;
46128c2ecf20Sopenharmony_ci		ofs += channels * 8;
46138c2ecf20Sopenharmony_ci		if (copy_u48_le(&peak_rms->playback_rms[i], hdsp->iobase + ofs,
46148c2ecf20Sopenharmony_ci				hdsp->iobase + ofs + 4))
46158c2ecf20Sopenharmony_ci			return -EFAULT;
46168c2ecf20Sopenharmony_ci		ofs += channels * 8;
46178c2ecf20Sopenharmony_ci		if (copy_u48_le(&peak_rms->output_rms[i], hdsp->iobase + ofs,
46188c2ecf20Sopenharmony_ci				hdsp->iobase + ofs + 4))
46198c2ecf20Sopenharmony_ci			return -EFAULT;
46208c2ecf20Sopenharmony_ci		j++;
46218c2ecf20Sopenharmony_ci	}
46228c2ecf20Sopenharmony_ci	return 0;
46238c2ecf20Sopenharmony_ci}
46248c2ecf20Sopenharmony_ci
46258c2ecf20Sopenharmony_cistatic int hdsp_9632_get_peak(struct hdsp *hdsp, struct hdsp_peak_rms __user *peak_rms)
46268c2ecf20Sopenharmony_ci{
46278c2ecf20Sopenharmony_ci	int i, j;
46288c2ecf20Sopenharmony_ci	struct hdsp_9632_meters __iomem *m;
46298c2ecf20Sopenharmony_ci	int doublespeed = 0;
46308c2ecf20Sopenharmony_ci
46318c2ecf20Sopenharmony_ci	if (hdsp_read (hdsp, HDSP_statusRegister) & HDSP_DoubleSpeedStatus)
46328c2ecf20Sopenharmony_ci		doublespeed = 1;
46338c2ecf20Sopenharmony_ci	m = (struct hdsp_9632_meters __iomem *)(hdsp->iobase+HDSP_9632_metersBase);
46348c2ecf20Sopenharmony_ci	for (i = 0, j = 0; i < 16; ++i, ++j) {
46358c2ecf20Sopenharmony_ci		if (copy_u32_le(&peak_rms->input_peaks[i], &m->input_peak[j]))
46368c2ecf20Sopenharmony_ci			return -EFAULT;
46378c2ecf20Sopenharmony_ci		if (copy_u32_le(&peak_rms->playback_peaks[i], &m->playback_peak[j]))
46388c2ecf20Sopenharmony_ci			return -EFAULT;
46398c2ecf20Sopenharmony_ci		if (copy_u32_le(&peak_rms->output_peaks[i], &m->output_peak[j]))
46408c2ecf20Sopenharmony_ci			return -EFAULT;
46418c2ecf20Sopenharmony_ci		if (copy_u64_le(&peak_rms->input_rms[i], &m->input_rms_low[j],
46428c2ecf20Sopenharmony_ci				&m->input_rms_high[j]))
46438c2ecf20Sopenharmony_ci			return -EFAULT;
46448c2ecf20Sopenharmony_ci		if (copy_u64_le(&peak_rms->playback_rms[i], &m->playback_rms_low[j],
46458c2ecf20Sopenharmony_ci				&m->playback_rms_high[j]))
46468c2ecf20Sopenharmony_ci			return -EFAULT;
46478c2ecf20Sopenharmony_ci		if (copy_u64_le(&peak_rms->output_rms[i], &m->output_rms_low[j],
46488c2ecf20Sopenharmony_ci				&m->output_rms_high[j]))
46498c2ecf20Sopenharmony_ci			return -EFAULT;
46508c2ecf20Sopenharmony_ci		if (doublespeed && i == 3) i += 4;
46518c2ecf20Sopenharmony_ci	}
46528c2ecf20Sopenharmony_ci	return 0;
46538c2ecf20Sopenharmony_ci}
46548c2ecf20Sopenharmony_ci
46558c2ecf20Sopenharmony_cistatic int hdsp_get_peak(struct hdsp *hdsp, struct hdsp_peak_rms __user *peak_rms)
46568c2ecf20Sopenharmony_ci{
46578c2ecf20Sopenharmony_ci	int i;
46588c2ecf20Sopenharmony_ci
46598c2ecf20Sopenharmony_ci	for (i = 0; i < 26; i++) {
46608c2ecf20Sopenharmony_ci		if (copy_u32_le(&peak_rms->playback_peaks[i],
46618c2ecf20Sopenharmony_ci				hdsp->iobase + HDSP_playbackPeakLevel + i * 4))
46628c2ecf20Sopenharmony_ci			return -EFAULT;
46638c2ecf20Sopenharmony_ci		if (copy_u32_le(&peak_rms->input_peaks[i],
46648c2ecf20Sopenharmony_ci				hdsp->iobase + HDSP_inputPeakLevel + i * 4))
46658c2ecf20Sopenharmony_ci			return -EFAULT;
46668c2ecf20Sopenharmony_ci	}
46678c2ecf20Sopenharmony_ci	for (i = 0; i < 28; i++) {
46688c2ecf20Sopenharmony_ci		if (copy_u32_le(&peak_rms->output_peaks[i],
46698c2ecf20Sopenharmony_ci				hdsp->iobase + HDSP_outputPeakLevel + i * 4))
46708c2ecf20Sopenharmony_ci			return -EFAULT;
46718c2ecf20Sopenharmony_ci	}
46728c2ecf20Sopenharmony_ci	for (i = 0; i < 26; ++i) {
46738c2ecf20Sopenharmony_ci		if (copy_u64_le(&peak_rms->playback_rms[i],
46748c2ecf20Sopenharmony_ci				hdsp->iobase + HDSP_playbackRmsLevel + i * 8 + 4,
46758c2ecf20Sopenharmony_ci				hdsp->iobase + HDSP_playbackRmsLevel + i * 8))
46768c2ecf20Sopenharmony_ci			return -EFAULT;
46778c2ecf20Sopenharmony_ci		if (copy_u64_le(&peak_rms->input_rms[i],
46788c2ecf20Sopenharmony_ci				hdsp->iobase + HDSP_inputRmsLevel + i * 8 + 4,
46798c2ecf20Sopenharmony_ci				hdsp->iobase + HDSP_inputRmsLevel + i * 8))
46808c2ecf20Sopenharmony_ci			return -EFAULT;
46818c2ecf20Sopenharmony_ci	}
46828c2ecf20Sopenharmony_ci	return 0;
46838c2ecf20Sopenharmony_ci}
46848c2ecf20Sopenharmony_ci
46858c2ecf20Sopenharmony_cistatic int snd_hdsp_hwdep_ioctl(struct snd_hwdep *hw, struct file *file, unsigned int cmd, unsigned long arg)
46868c2ecf20Sopenharmony_ci{
46878c2ecf20Sopenharmony_ci	struct hdsp *hdsp = hw->private_data;
46888c2ecf20Sopenharmony_ci	void __user *argp = (void __user *)arg;
46898c2ecf20Sopenharmony_ci	int err;
46908c2ecf20Sopenharmony_ci
46918c2ecf20Sopenharmony_ci	switch (cmd) {
46928c2ecf20Sopenharmony_ci	case SNDRV_HDSP_IOCTL_GET_PEAK_RMS: {
46938c2ecf20Sopenharmony_ci		struct hdsp_peak_rms __user *peak_rms = (struct hdsp_peak_rms __user *)arg;
46948c2ecf20Sopenharmony_ci
46958c2ecf20Sopenharmony_ci		err = hdsp_check_for_iobox(hdsp);
46968c2ecf20Sopenharmony_ci		if (err < 0)
46978c2ecf20Sopenharmony_ci			return err;
46988c2ecf20Sopenharmony_ci
46998c2ecf20Sopenharmony_ci		err = hdsp_check_for_firmware(hdsp, 1);
47008c2ecf20Sopenharmony_ci		if (err < 0)
47018c2ecf20Sopenharmony_ci			return err;
47028c2ecf20Sopenharmony_ci
47038c2ecf20Sopenharmony_ci		if (!(hdsp->state & HDSP_FirmwareLoaded)) {
47048c2ecf20Sopenharmony_ci			dev_err(hdsp->card->dev,
47058c2ecf20Sopenharmony_ci				"firmware needs to be uploaded to the card.\n");
47068c2ecf20Sopenharmony_ci			return -EINVAL;
47078c2ecf20Sopenharmony_ci		}
47088c2ecf20Sopenharmony_ci
47098c2ecf20Sopenharmony_ci		switch (hdsp->io_type) {
47108c2ecf20Sopenharmony_ci		case H9652:
47118c2ecf20Sopenharmony_ci			return hdsp_9652_get_peak(hdsp, peak_rms);
47128c2ecf20Sopenharmony_ci		case H9632:
47138c2ecf20Sopenharmony_ci			return hdsp_9632_get_peak(hdsp, peak_rms);
47148c2ecf20Sopenharmony_ci		default:
47158c2ecf20Sopenharmony_ci			return hdsp_get_peak(hdsp, peak_rms);
47168c2ecf20Sopenharmony_ci		}
47178c2ecf20Sopenharmony_ci	}
47188c2ecf20Sopenharmony_ci	case SNDRV_HDSP_IOCTL_GET_CONFIG_INFO: {
47198c2ecf20Sopenharmony_ci		struct hdsp_config_info info;
47208c2ecf20Sopenharmony_ci		unsigned long flags;
47218c2ecf20Sopenharmony_ci		int i;
47228c2ecf20Sopenharmony_ci
47238c2ecf20Sopenharmony_ci		err = hdsp_check_for_iobox(hdsp);
47248c2ecf20Sopenharmony_ci		if (err < 0)
47258c2ecf20Sopenharmony_ci			return err;
47268c2ecf20Sopenharmony_ci
47278c2ecf20Sopenharmony_ci		err = hdsp_check_for_firmware(hdsp, 1);
47288c2ecf20Sopenharmony_ci		if (err < 0)
47298c2ecf20Sopenharmony_ci			return err;
47308c2ecf20Sopenharmony_ci
47318c2ecf20Sopenharmony_ci		memset(&info, 0, sizeof(info));
47328c2ecf20Sopenharmony_ci		spin_lock_irqsave(&hdsp->lock, flags);
47338c2ecf20Sopenharmony_ci		info.pref_sync_ref = (unsigned char)hdsp_pref_sync_ref(hdsp);
47348c2ecf20Sopenharmony_ci		info.wordclock_sync_check = (unsigned char)hdsp_wc_sync_check(hdsp);
47358c2ecf20Sopenharmony_ci		if (hdsp->io_type != H9632)
47368c2ecf20Sopenharmony_ci		    info.adatsync_sync_check = (unsigned char)hdsp_adatsync_sync_check(hdsp);
47378c2ecf20Sopenharmony_ci		info.spdif_sync_check = (unsigned char)hdsp_spdif_sync_check(hdsp);
47388c2ecf20Sopenharmony_ci		for (i = 0; i < ((hdsp->io_type != Multiface && hdsp->io_type != RPM && hdsp->io_type != H9632) ? 3 : 1); ++i)
47398c2ecf20Sopenharmony_ci			info.adat_sync_check[i] = (unsigned char)hdsp_adat_sync_check(hdsp, i);
47408c2ecf20Sopenharmony_ci		info.spdif_in = (unsigned char)hdsp_spdif_in(hdsp);
47418c2ecf20Sopenharmony_ci		info.spdif_out = (unsigned char)hdsp_toggle_setting(hdsp,
47428c2ecf20Sopenharmony_ci				HDSP_SPDIFOpticalOut);
47438c2ecf20Sopenharmony_ci		info.spdif_professional = (unsigned char)
47448c2ecf20Sopenharmony_ci			hdsp_toggle_setting(hdsp, HDSP_SPDIFProfessional);
47458c2ecf20Sopenharmony_ci		info.spdif_emphasis = (unsigned char)
47468c2ecf20Sopenharmony_ci			hdsp_toggle_setting(hdsp, HDSP_SPDIFEmphasis);
47478c2ecf20Sopenharmony_ci		info.spdif_nonaudio = (unsigned char)
47488c2ecf20Sopenharmony_ci			hdsp_toggle_setting(hdsp, HDSP_SPDIFNonAudio);
47498c2ecf20Sopenharmony_ci		info.spdif_sample_rate = hdsp_spdif_sample_rate(hdsp);
47508c2ecf20Sopenharmony_ci		info.system_sample_rate = hdsp->system_sample_rate;
47518c2ecf20Sopenharmony_ci		info.autosync_sample_rate = hdsp_external_sample_rate(hdsp);
47528c2ecf20Sopenharmony_ci		info.system_clock_mode = (unsigned char)hdsp_system_clock_mode(hdsp);
47538c2ecf20Sopenharmony_ci		info.clock_source = (unsigned char)hdsp_clock_source(hdsp);
47548c2ecf20Sopenharmony_ci		info.autosync_ref = (unsigned char)hdsp_autosync_ref(hdsp);
47558c2ecf20Sopenharmony_ci		info.line_out = (unsigned char)
47568c2ecf20Sopenharmony_ci			hdsp_toggle_setting(hdsp, HDSP_LineOut);
47578c2ecf20Sopenharmony_ci		if (hdsp->io_type == H9632) {
47588c2ecf20Sopenharmony_ci			info.da_gain = (unsigned char)hdsp_da_gain(hdsp);
47598c2ecf20Sopenharmony_ci			info.ad_gain = (unsigned char)hdsp_ad_gain(hdsp);
47608c2ecf20Sopenharmony_ci			info.phone_gain = (unsigned char)hdsp_phone_gain(hdsp);
47618c2ecf20Sopenharmony_ci			info.xlr_breakout_cable =
47628c2ecf20Sopenharmony_ci				(unsigned char)hdsp_toggle_setting(hdsp,
47638c2ecf20Sopenharmony_ci					HDSP_XLRBreakoutCable);
47648c2ecf20Sopenharmony_ci
47658c2ecf20Sopenharmony_ci		} else if (hdsp->io_type == RPM) {
47668c2ecf20Sopenharmony_ci			info.da_gain = (unsigned char) hdsp_rpm_input12(hdsp);
47678c2ecf20Sopenharmony_ci			info.ad_gain = (unsigned char) hdsp_rpm_input34(hdsp);
47688c2ecf20Sopenharmony_ci		}
47698c2ecf20Sopenharmony_ci		if (hdsp->io_type == H9632 || hdsp->io_type == H9652)
47708c2ecf20Sopenharmony_ci			info.analog_extension_board =
47718c2ecf20Sopenharmony_ci				(unsigned char)hdsp_toggle_setting(hdsp,
47728c2ecf20Sopenharmony_ci					    HDSP_AnalogExtensionBoard);
47738c2ecf20Sopenharmony_ci		spin_unlock_irqrestore(&hdsp->lock, flags);
47748c2ecf20Sopenharmony_ci		if (copy_to_user(argp, &info, sizeof(info)))
47758c2ecf20Sopenharmony_ci			return -EFAULT;
47768c2ecf20Sopenharmony_ci		break;
47778c2ecf20Sopenharmony_ci	}
47788c2ecf20Sopenharmony_ci	case SNDRV_HDSP_IOCTL_GET_9632_AEB: {
47798c2ecf20Sopenharmony_ci		struct hdsp_9632_aeb h9632_aeb;
47808c2ecf20Sopenharmony_ci
47818c2ecf20Sopenharmony_ci		if (hdsp->io_type != H9632) return -EINVAL;
47828c2ecf20Sopenharmony_ci		h9632_aeb.aebi = hdsp->ss_in_channels - H9632_SS_CHANNELS;
47838c2ecf20Sopenharmony_ci		h9632_aeb.aebo = hdsp->ss_out_channels - H9632_SS_CHANNELS;
47848c2ecf20Sopenharmony_ci		if (copy_to_user(argp, &h9632_aeb, sizeof(h9632_aeb)))
47858c2ecf20Sopenharmony_ci			return -EFAULT;
47868c2ecf20Sopenharmony_ci		break;
47878c2ecf20Sopenharmony_ci	}
47888c2ecf20Sopenharmony_ci	case SNDRV_HDSP_IOCTL_GET_VERSION: {
47898c2ecf20Sopenharmony_ci		struct hdsp_version hdsp_version;
47908c2ecf20Sopenharmony_ci		int err;
47918c2ecf20Sopenharmony_ci
47928c2ecf20Sopenharmony_ci		if (hdsp->io_type == H9652 || hdsp->io_type == H9632) return -EINVAL;
47938c2ecf20Sopenharmony_ci		if (hdsp->io_type == Undefined) {
47948c2ecf20Sopenharmony_ci			if ((err = hdsp_get_iobox_version(hdsp)) < 0)
47958c2ecf20Sopenharmony_ci				return err;
47968c2ecf20Sopenharmony_ci		}
47978c2ecf20Sopenharmony_ci		memset(&hdsp_version, 0, sizeof(hdsp_version));
47988c2ecf20Sopenharmony_ci		hdsp_version.io_type = hdsp->io_type;
47998c2ecf20Sopenharmony_ci		hdsp_version.firmware_rev = hdsp->firmware_rev;
48008c2ecf20Sopenharmony_ci		if ((err = copy_to_user(argp, &hdsp_version, sizeof(hdsp_version))))
48018c2ecf20Sopenharmony_ci		    	return -EFAULT;
48028c2ecf20Sopenharmony_ci		break;
48038c2ecf20Sopenharmony_ci	}
48048c2ecf20Sopenharmony_ci	case SNDRV_HDSP_IOCTL_UPLOAD_FIRMWARE: {
48058c2ecf20Sopenharmony_ci		struct hdsp_firmware firmware;
48068c2ecf20Sopenharmony_ci		u32 __user *firmware_data;
48078c2ecf20Sopenharmony_ci		int err;
48088c2ecf20Sopenharmony_ci
48098c2ecf20Sopenharmony_ci		if (hdsp->io_type == H9652 || hdsp->io_type == H9632) return -EINVAL;
48108c2ecf20Sopenharmony_ci		/* SNDRV_HDSP_IOCTL_GET_VERSION must have been called */
48118c2ecf20Sopenharmony_ci		if (hdsp->io_type == Undefined) return -EINVAL;
48128c2ecf20Sopenharmony_ci
48138c2ecf20Sopenharmony_ci		if (hdsp->state & (HDSP_FirmwareCached | HDSP_FirmwareLoaded))
48148c2ecf20Sopenharmony_ci			return -EBUSY;
48158c2ecf20Sopenharmony_ci
48168c2ecf20Sopenharmony_ci		dev_info(hdsp->card->dev,
48178c2ecf20Sopenharmony_ci			 "initializing firmware upload\n");
48188c2ecf20Sopenharmony_ci		if (copy_from_user(&firmware, argp, sizeof(firmware)))
48198c2ecf20Sopenharmony_ci			return -EFAULT;
48208c2ecf20Sopenharmony_ci		firmware_data = (u32 __user *)firmware.firmware_data;
48218c2ecf20Sopenharmony_ci
48228c2ecf20Sopenharmony_ci		if (hdsp_check_for_iobox (hdsp))
48238c2ecf20Sopenharmony_ci			return -EIO;
48248c2ecf20Sopenharmony_ci
48258c2ecf20Sopenharmony_ci		if (!hdsp->fw_uploaded) {
48268c2ecf20Sopenharmony_ci			hdsp->fw_uploaded = vmalloc(HDSP_FIRMWARE_SIZE);
48278c2ecf20Sopenharmony_ci			if (!hdsp->fw_uploaded)
48288c2ecf20Sopenharmony_ci				return -ENOMEM;
48298c2ecf20Sopenharmony_ci		}
48308c2ecf20Sopenharmony_ci
48318c2ecf20Sopenharmony_ci		if (copy_from_user(hdsp->fw_uploaded, firmware_data,
48328c2ecf20Sopenharmony_ci				   HDSP_FIRMWARE_SIZE)) {
48338c2ecf20Sopenharmony_ci			vfree(hdsp->fw_uploaded);
48348c2ecf20Sopenharmony_ci			hdsp->fw_uploaded = NULL;
48358c2ecf20Sopenharmony_ci			return -EFAULT;
48368c2ecf20Sopenharmony_ci		}
48378c2ecf20Sopenharmony_ci
48388c2ecf20Sopenharmony_ci		hdsp->state |= HDSP_FirmwareCached;
48398c2ecf20Sopenharmony_ci
48408c2ecf20Sopenharmony_ci		if ((err = snd_hdsp_load_firmware_from_cache(hdsp)) < 0)
48418c2ecf20Sopenharmony_ci			return err;
48428c2ecf20Sopenharmony_ci
48438c2ecf20Sopenharmony_ci		if (!(hdsp->state & HDSP_InitializationComplete)) {
48448c2ecf20Sopenharmony_ci			if ((err = snd_hdsp_enable_io(hdsp)) < 0)
48458c2ecf20Sopenharmony_ci				return err;
48468c2ecf20Sopenharmony_ci
48478c2ecf20Sopenharmony_ci			snd_hdsp_initialize_channels(hdsp);
48488c2ecf20Sopenharmony_ci			snd_hdsp_initialize_midi_flush(hdsp);
48498c2ecf20Sopenharmony_ci
48508c2ecf20Sopenharmony_ci			if ((err = snd_hdsp_create_alsa_devices(hdsp->card, hdsp)) < 0) {
48518c2ecf20Sopenharmony_ci				dev_err(hdsp->card->dev,
48528c2ecf20Sopenharmony_ci					"error creating alsa devices\n");
48538c2ecf20Sopenharmony_ci				return err;
48548c2ecf20Sopenharmony_ci			}
48558c2ecf20Sopenharmony_ci		}
48568c2ecf20Sopenharmony_ci		break;
48578c2ecf20Sopenharmony_ci	}
48588c2ecf20Sopenharmony_ci	case SNDRV_HDSP_IOCTL_GET_MIXER: {
48598c2ecf20Sopenharmony_ci		struct hdsp_mixer __user *mixer = (struct hdsp_mixer __user *)argp;
48608c2ecf20Sopenharmony_ci		if (copy_to_user(mixer->matrix, hdsp->mixer_matrix, sizeof(unsigned short)*HDSP_MATRIX_MIXER_SIZE))
48618c2ecf20Sopenharmony_ci			return -EFAULT;
48628c2ecf20Sopenharmony_ci		break;
48638c2ecf20Sopenharmony_ci	}
48648c2ecf20Sopenharmony_ci	default:
48658c2ecf20Sopenharmony_ci		return -EINVAL;
48668c2ecf20Sopenharmony_ci	}
48678c2ecf20Sopenharmony_ci	return 0;
48688c2ecf20Sopenharmony_ci}
48698c2ecf20Sopenharmony_ci
48708c2ecf20Sopenharmony_cistatic const struct snd_pcm_ops snd_hdsp_playback_ops = {
48718c2ecf20Sopenharmony_ci	.open =		snd_hdsp_playback_open,
48728c2ecf20Sopenharmony_ci	.close =	snd_hdsp_playback_release,
48738c2ecf20Sopenharmony_ci	.ioctl =	snd_hdsp_ioctl,
48748c2ecf20Sopenharmony_ci	.hw_params =	snd_hdsp_hw_params,
48758c2ecf20Sopenharmony_ci	.prepare =	snd_hdsp_prepare,
48768c2ecf20Sopenharmony_ci	.trigger =	snd_hdsp_trigger,
48778c2ecf20Sopenharmony_ci	.pointer =	snd_hdsp_hw_pointer,
48788c2ecf20Sopenharmony_ci	.copy_user =	snd_hdsp_playback_copy,
48798c2ecf20Sopenharmony_ci	.copy_kernel =	snd_hdsp_playback_copy_kernel,
48808c2ecf20Sopenharmony_ci	.fill_silence =	snd_hdsp_hw_silence,
48818c2ecf20Sopenharmony_ci};
48828c2ecf20Sopenharmony_ci
48838c2ecf20Sopenharmony_cistatic const struct snd_pcm_ops snd_hdsp_capture_ops = {
48848c2ecf20Sopenharmony_ci	.open =		snd_hdsp_capture_open,
48858c2ecf20Sopenharmony_ci	.close =	snd_hdsp_capture_release,
48868c2ecf20Sopenharmony_ci	.ioctl =	snd_hdsp_ioctl,
48878c2ecf20Sopenharmony_ci	.hw_params =	snd_hdsp_hw_params,
48888c2ecf20Sopenharmony_ci	.prepare =	snd_hdsp_prepare,
48898c2ecf20Sopenharmony_ci	.trigger =	snd_hdsp_trigger,
48908c2ecf20Sopenharmony_ci	.pointer =	snd_hdsp_hw_pointer,
48918c2ecf20Sopenharmony_ci	.copy_user =	snd_hdsp_capture_copy,
48928c2ecf20Sopenharmony_ci	.copy_kernel =	snd_hdsp_capture_copy_kernel,
48938c2ecf20Sopenharmony_ci};
48948c2ecf20Sopenharmony_ci
48958c2ecf20Sopenharmony_cistatic int snd_hdsp_create_hwdep(struct snd_card *card, struct hdsp *hdsp)
48968c2ecf20Sopenharmony_ci{
48978c2ecf20Sopenharmony_ci	struct snd_hwdep *hw;
48988c2ecf20Sopenharmony_ci	int err;
48998c2ecf20Sopenharmony_ci
49008c2ecf20Sopenharmony_ci	if ((err = snd_hwdep_new(card, "HDSP hwdep", 0, &hw)) < 0)
49018c2ecf20Sopenharmony_ci		return err;
49028c2ecf20Sopenharmony_ci
49038c2ecf20Sopenharmony_ci	hdsp->hwdep = hw;
49048c2ecf20Sopenharmony_ci	hw->private_data = hdsp;
49058c2ecf20Sopenharmony_ci	strcpy(hw->name, "HDSP hwdep interface");
49068c2ecf20Sopenharmony_ci
49078c2ecf20Sopenharmony_ci	hw->ops.ioctl = snd_hdsp_hwdep_ioctl;
49088c2ecf20Sopenharmony_ci	hw->ops.ioctl_compat = snd_hdsp_hwdep_ioctl;
49098c2ecf20Sopenharmony_ci
49108c2ecf20Sopenharmony_ci	return 0;
49118c2ecf20Sopenharmony_ci}
49128c2ecf20Sopenharmony_ci
49138c2ecf20Sopenharmony_cistatic int snd_hdsp_create_pcm(struct snd_card *card, struct hdsp *hdsp)
49148c2ecf20Sopenharmony_ci{
49158c2ecf20Sopenharmony_ci	struct snd_pcm *pcm;
49168c2ecf20Sopenharmony_ci	int err;
49178c2ecf20Sopenharmony_ci
49188c2ecf20Sopenharmony_ci	if ((err = snd_pcm_new(card, hdsp->card_name, 0, 1, 1, &pcm)) < 0)
49198c2ecf20Sopenharmony_ci		return err;
49208c2ecf20Sopenharmony_ci
49218c2ecf20Sopenharmony_ci	hdsp->pcm = pcm;
49228c2ecf20Sopenharmony_ci	pcm->private_data = hdsp;
49238c2ecf20Sopenharmony_ci	strcpy(pcm->name, hdsp->card_name);
49248c2ecf20Sopenharmony_ci
49258c2ecf20Sopenharmony_ci	snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &snd_hdsp_playback_ops);
49268c2ecf20Sopenharmony_ci	snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &snd_hdsp_capture_ops);
49278c2ecf20Sopenharmony_ci
49288c2ecf20Sopenharmony_ci	pcm->info_flags = SNDRV_PCM_INFO_JOINT_DUPLEX;
49298c2ecf20Sopenharmony_ci
49308c2ecf20Sopenharmony_ci	return 0;
49318c2ecf20Sopenharmony_ci}
49328c2ecf20Sopenharmony_ci
49338c2ecf20Sopenharmony_cistatic void snd_hdsp_9652_enable_mixer (struct hdsp *hdsp)
49348c2ecf20Sopenharmony_ci{
49358c2ecf20Sopenharmony_ci        hdsp->control2_register |= HDSP_9652_ENABLE_MIXER;
49368c2ecf20Sopenharmony_ci	hdsp_write (hdsp, HDSP_control2Reg, hdsp->control2_register);
49378c2ecf20Sopenharmony_ci}
49388c2ecf20Sopenharmony_ci
49398c2ecf20Sopenharmony_cistatic int snd_hdsp_enable_io (struct hdsp *hdsp)
49408c2ecf20Sopenharmony_ci{
49418c2ecf20Sopenharmony_ci	int i;
49428c2ecf20Sopenharmony_ci
49438c2ecf20Sopenharmony_ci	if (hdsp_fifo_wait (hdsp, 0, 100)) {
49448c2ecf20Sopenharmony_ci		dev_err(hdsp->card->dev,
49458c2ecf20Sopenharmony_ci			"enable_io fifo_wait failed\n");
49468c2ecf20Sopenharmony_ci		return -EIO;
49478c2ecf20Sopenharmony_ci	}
49488c2ecf20Sopenharmony_ci
49498c2ecf20Sopenharmony_ci	for (i = 0; i < hdsp->max_channels; ++i) {
49508c2ecf20Sopenharmony_ci		hdsp_write (hdsp, HDSP_inputEnable + (4 * i), 1);
49518c2ecf20Sopenharmony_ci		hdsp_write (hdsp, HDSP_outputEnable + (4 * i), 1);
49528c2ecf20Sopenharmony_ci	}
49538c2ecf20Sopenharmony_ci
49548c2ecf20Sopenharmony_ci	return 0;
49558c2ecf20Sopenharmony_ci}
49568c2ecf20Sopenharmony_ci
49578c2ecf20Sopenharmony_cistatic void snd_hdsp_initialize_channels(struct hdsp *hdsp)
49588c2ecf20Sopenharmony_ci{
49598c2ecf20Sopenharmony_ci	int status, aebi_channels, aebo_channels;
49608c2ecf20Sopenharmony_ci
49618c2ecf20Sopenharmony_ci	switch (hdsp->io_type) {
49628c2ecf20Sopenharmony_ci	case Digiface:
49638c2ecf20Sopenharmony_ci		hdsp->card_name = "RME Hammerfall DSP + Digiface";
49648c2ecf20Sopenharmony_ci		hdsp->ss_in_channels = hdsp->ss_out_channels = DIGIFACE_SS_CHANNELS;
49658c2ecf20Sopenharmony_ci		hdsp->ds_in_channels = hdsp->ds_out_channels = DIGIFACE_DS_CHANNELS;
49668c2ecf20Sopenharmony_ci		break;
49678c2ecf20Sopenharmony_ci
49688c2ecf20Sopenharmony_ci	case H9652:
49698c2ecf20Sopenharmony_ci		hdsp->card_name = "RME Hammerfall HDSP 9652";
49708c2ecf20Sopenharmony_ci		hdsp->ss_in_channels = hdsp->ss_out_channels = H9652_SS_CHANNELS;
49718c2ecf20Sopenharmony_ci		hdsp->ds_in_channels = hdsp->ds_out_channels = H9652_DS_CHANNELS;
49728c2ecf20Sopenharmony_ci		break;
49738c2ecf20Sopenharmony_ci
49748c2ecf20Sopenharmony_ci	case H9632:
49758c2ecf20Sopenharmony_ci		status = hdsp_read(hdsp, HDSP_statusRegister);
49768c2ecf20Sopenharmony_ci		/* HDSP_AEBx bits are low when AEB are connected */
49778c2ecf20Sopenharmony_ci		aebi_channels = (status & HDSP_AEBI) ? 0 : 4;
49788c2ecf20Sopenharmony_ci		aebo_channels = (status & HDSP_AEBO) ? 0 : 4;
49798c2ecf20Sopenharmony_ci		hdsp->card_name = "RME Hammerfall HDSP 9632";
49808c2ecf20Sopenharmony_ci		hdsp->ss_in_channels = H9632_SS_CHANNELS+aebi_channels;
49818c2ecf20Sopenharmony_ci		hdsp->ds_in_channels = H9632_DS_CHANNELS+aebi_channels;
49828c2ecf20Sopenharmony_ci		hdsp->qs_in_channels = H9632_QS_CHANNELS+aebi_channels;
49838c2ecf20Sopenharmony_ci		hdsp->ss_out_channels = H9632_SS_CHANNELS+aebo_channels;
49848c2ecf20Sopenharmony_ci		hdsp->ds_out_channels = H9632_DS_CHANNELS+aebo_channels;
49858c2ecf20Sopenharmony_ci		hdsp->qs_out_channels = H9632_QS_CHANNELS+aebo_channels;
49868c2ecf20Sopenharmony_ci		break;
49878c2ecf20Sopenharmony_ci
49888c2ecf20Sopenharmony_ci	case Multiface:
49898c2ecf20Sopenharmony_ci		hdsp->card_name = "RME Hammerfall DSP + Multiface";
49908c2ecf20Sopenharmony_ci		hdsp->ss_in_channels = hdsp->ss_out_channels = MULTIFACE_SS_CHANNELS;
49918c2ecf20Sopenharmony_ci		hdsp->ds_in_channels = hdsp->ds_out_channels = MULTIFACE_DS_CHANNELS;
49928c2ecf20Sopenharmony_ci		break;
49938c2ecf20Sopenharmony_ci
49948c2ecf20Sopenharmony_ci	case RPM:
49958c2ecf20Sopenharmony_ci		hdsp->card_name = "RME Hammerfall DSP + RPM";
49968c2ecf20Sopenharmony_ci		hdsp->ss_in_channels = RPM_CHANNELS-1;
49978c2ecf20Sopenharmony_ci		hdsp->ss_out_channels = RPM_CHANNELS;
49988c2ecf20Sopenharmony_ci		hdsp->ds_in_channels = RPM_CHANNELS-1;
49998c2ecf20Sopenharmony_ci		hdsp->ds_out_channels = RPM_CHANNELS;
50008c2ecf20Sopenharmony_ci		break;
50018c2ecf20Sopenharmony_ci
50028c2ecf20Sopenharmony_ci	default:
50038c2ecf20Sopenharmony_ci 		/* should never get here */
50048c2ecf20Sopenharmony_ci		break;
50058c2ecf20Sopenharmony_ci	}
50068c2ecf20Sopenharmony_ci}
50078c2ecf20Sopenharmony_ci
50088c2ecf20Sopenharmony_cistatic void snd_hdsp_initialize_midi_flush (struct hdsp *hdsp)
50098c2ecf20Sopenharmony_ci{
50108c2ecf20Sopenharmony_ci	snd_hdsp_flush_midi_input (hdsp, 0);
50118c2ecf20Sopenharmony_ci	snd_hdsp_flush_midi_input (hdsp, 1);
50128c2ecf20Sopenharmony_ci}
50138c2ecf20Sopenharmony_ci
50148c2ecf20Sopenharmony_cistatic int snd_hdsp_create_alsa_devices(struct snd_card *card, struct hdsp *hdsp)
50158c2ecf20Sopenharmony_ci{
50168c2ecf20Sopenharmony_ci	int err;
50178c2ecf20Sopenharmony_ci
50188c2ecf20Sopenharmony_ci	if ((err = snd_hdsp_create_pcm(card, hdsp)) < 0) {
50198c2ecf20Sopenharmony_ci		dev_err(card->dev,
50208c2ecf20Sopenharmony_ci			"Error creating pcm interface\n");
50218c2ecf20Sopenharmony_ci		return err;
50228c2ecf20Sopenharmony_ci	}
50238c2ecf20Sopenharmony_ci
50248c2ecf20Sopenharmony_ci
50258c2ecf20Sopenharmony_ci	if ((err = snd_hdsp_create_midi(card, hdsp, 0)) < 0) {
50268c2ecf20Sopenharmony_ci		dev_err(card->dev,
50278c2ecf20Sopenharmony_ci			"Error creating first midi interface\n");
50288c2ecf20Sopenharmony_ci		return err;
50298c2ecf20Sopenharmony_ci	}
50308c2ecf20Sopenharmony_ci
50318c2ecf20Sopenharmony_ci	if (hdsp->io_type == Digiface || hdsp->io_type == H9652) {
50328c2ecf20Sopenharmony_ci		if ((err = snd_hdsp_create_midi(card, hdsp, 1)) < 0) {
50338c2ecf20Sopenharmony_ci			dev_err(card->dev,
50348c2ecf20Sopenharmony_ci				"Error creating second midi interface\n");
50358c2ecf20Sopenharmony_ci			return err;
50368c2ecf20Sopenharmony_ci		}
50378c2ecf20Sopenharmony_ci	}
50388c2ecf20Sopenharmony_ci
50398c2ecf20Sopenharmony_ci	if ((err = snd_hdsp_create_controls(card, hdsp)) < 0) {
50408c2ecf20Sopenharmony_ci		dev_err(card->dev,
50418c2ecf20Sopenharmony_ci			"Error creating ctl interface\n");
50428c2ecf20Sopenharmony_ci		return err;
50438c2ecf20Sopenharmony_ci	}
50448c2ecf20Sopenharmony_ci
50458c2ecf20Sopenharmony_ci	snd_hdsp_proc_init(hdsp);
50468c2ecf20Sopenharmony_ci
50478c2ecf20Sopenharmony_ci	hdsp->system_sample_rate = -1;
50488c2ecf20Sopenharmony_ci	hdsp->playback_pid = -1;
50498c2ecf20Sopenharmony_ci	hdsp->capture_pid = -1;
50508c2ecf20Sopenharmony_ci	hdsp->capture_substream = NULL;
50518c2ecf20Sopenharmony_ci	hdsp->playback_substream = NULL;
50528c2ecf20Sopenharmony_ci
50538c2ecf20Sopenharmony_ci	if ((err = snd_hdsp_set_defaults(hdsp)) < 0) {
50548c2ecf20Sopenharmony_ci		dev_err(card->dev,
50558c2ecf20Sopenharmony_ci			"Error setting default values\n");
50568c2ecf20Sopenharmony_ci		return err;
50578c2ecf20Sopenharmony_ci	}
50588c2ecf20Sopenharmony_ci
50598c2ecf20Sopenharmony_ci	if (!(hdsp->state & HDSP_InitializationComplete)) {
50608c2ecf20Sopenharmony_ci		strcpy(card->shortname, "Hammerfall DSP");
50618c2ecf20Sopenharmony_ci		sprintf(card->longname, "%s at 0x%lx, irq %d", hdsp->card_name,
50628c2ecf20Sopenharmony_ci			hdsp->port, hdsp->irq);
50638c2ecf20Sopenharmony_ci
50648c2ecf20Sopenharmony_ci		if ((err = snd_card_register(card)) < 0) {
50658c2ecf20Sopenharmony_ci			dev_err(card->dev,
50668c2ecf20Sopenharmony_ci				"error registering card\n");
50678c2ecf20Sopenharmony_ci			return err;
50688c2ecf20Sopenharmony_ci		}
50698c2ecf20Sopenharmony_ci		hdsp->state |= HDSP_InitializationComplete;
50708c2ecf20Sopenharmony_ci	}
50718c2ecf20Sopenharmony_ci
50728c2ecf20Sopenharmony_ci	return 0;
50738c2ecf20Sopenharmony_ci}
50748c2ecf20Sopenharmony_ci
50758c2ecf20Sopenharmony_ci/* load firmware via hotplug fw loader */
50768c2ecf20Sopenharmony_cistatic int hdsp_request_fw_loader(struct hdsp *hdsp)
50778c2ecf20Sopenharmony_ci{
50788c2ecf20Sopenharmony_ci	const char *fwfile;
50798c2ecf20Sopenharmony_ci	const struct firmware *fw;
50808c2ecf20Sopenharmony_ci	int err;
50818c2ecf20Sopenharmony_ci
50828c2ecf20Sopenharmony_ci	if (hdsp->io_type == H9652 || hdsp->io_type == H9632)
50838c2ecf20Sopenharmony_ci		return 0;
50848c2ecf20Sopenharmony_ci	if (hdsp->io_type == Undefined) {
50858c2ecf20Sopenharmony_ci		if ((err = hdsp_get_iobox_version(hdsp)) < 0)
50868c2ecf20Sopenharmony_ci			return err;
50878c2ecf20Sopenharmony_ci		if (hdsp->io_type == H9652 || hdsp->io_type == H9632)
50888c2ecf20Sopenharmony_ci			return 0;
50898c2ecf20Sopenharmony_ci	}
50908c2ecf20Sopenharmony_ci
50918c2ecf20Sopenharmony_ci	/* caution: max length of firmware filename is 30! */
50928c2ecf20Sopenharmony_ci	switch (hdsp->io_type) {
50938c2ecf20Sopenharmony_ci	case RPM:
50948c2ecf20Sopenharmony_ci		fwfile = "rpm_firmware.bin";
50958c2ecf20Sopenharmony_ci		break;
50968c2ecf20Sopenharmony_ci	case Multiface:
50978c2ecf20Sopenharmony_ci		if (hdsp->firmware_rev == 0xa)
50988c2ecf20Sopenharmony_ci			fwfile = "multiface_firmware.bin";
50998c2ecf20Sopenharmony_ci		else
51008c2ecf20Sopenharmony_ci			fwfile = "multiface_firmware_rev11.bin";
51018c2ecf20Sopenharmony_ci		break;
51028c2ecf20Sopenharmony_ci	case Digiface:
51038c2ecf20Sopenharmony_ci		if (hdsp->firmware_rev == 0xa)
51048c2ecf20Sopenharmony_ci			fwfile = "digiface_firmware.bin";
51058c2ecf20Sopenharmony_ci		else
51068c2ecf20Sopenharmony_ci			fwfile = "digiface_firmware_rev11.bin";
51078c2ecf20Sopenharmony_ci		break;
51088c2ecf20Sopenharmony_ci	default:
51098c2ecf20Sopenharmony_ci		dev_err(hdsp->card->dev,
51108c2ecf20Sopenharmony_ci			"invalid io_type %d\n", hdsp->io_type);
51118c2ecf20Sopenharmony_ci		return -EINVAL;
51128c2ecf20Sopenharmony_ci	}
51138c2ecf20Sopenharmony_ci
51148c2ecf20Sopenharmony_ci	if (request_firmware(&fw, fwfile, &hdsp->pci->dev)) {
51158c2ecf20Sopenharmony_ci		dev_err(hdsp->card->dev,
51168c2ecf20Sopenharmony_ci			"cannot load firmware %s\n", fwfile);
51178c2ecf20Sopenharmony_ci		return -ENOENT;
51188c2ecf20Sopenharmony_ci	}
51198c2ecf20Sopenharmony_ci	if (fw->size < HDSP_FIRMWARE_SIZE) {
51208c2ecf20Sopenharmony_ci		dev_err(hdsp->card->dev,
51218c2ecf20Sopenharmony_ci			"too short firmware size %d (expected %d)\n",
51228c2ecf20Sopenharmony_ci			   (int)fw->size, HDSP_FIRMWARE_SIZE);
51238c2ecf20Sopenharmony_ci		release_firmware(fw);
51248c2ecf20Sopenharmony_ci		return -EINVAL;
51258c2ecf20Sopenharmony_ci	}
51268c2ecf20Sopenharmony_ci
51278c2ecf20Sopenharmony_ci	hdsp->firmware = fw;
51288c2ecf20Sopenharmony_ci
51298c2ecf20Sopenharmony_ci	hdsp->state |= HDSP_FirmwareCached;
51308c2ecf20Sopenharmony_ci
51318c2ecf20Sopenharmony_ci	if ((err = snd_hdsp_load_firmware_from_cache(hdsp)) < 0)
51328c2ecf20Sopenharmony_ci		return err;
51338c2ecf20Sopenharmony_ci
51348c2ecf20Sopenharmony_ci	if (!(hdsp->state & HDSP_InitializationComplete)) {
51358c2ecf20Sopenharmony_ci		if ((err = snd_hdsp_enable_io(hdsp)) < 0)
51368c2ecf20Sopenharmony_ci			return err;
51378c2ecf20Sopenharmony_ci
51388c2ecf20Sopenharmony_ci		if ((err = snd_hdsp_create_hwdep(hdsp->card, hdsp)) < 0) {
51398c2ecf20Sopenharmony_ci			dev_err(hdsp->card->dev,
51408c2ecf20Sopenharmony_ci				"error creating hwdep device\n");
51418c2ecf20Sopenharmony_ci			return err;
51428c2ecf20Sopenharmony_ci		}
51438c2ecf20Sopenharmony_ci		snd_hdsp_initialize_channels(hdsp);
51448c2ecf20Sopenharmony_ci		snd_hdsp_initialize_midi_flush(hdsp);
51458c2ecf20Sopenharmony_ci		if ((err = snd_hdsp_create_alsa_devices(hdsp->card, hdsp)) < 0) {
51468c2ecf20Sopenharmony_ci			dev_err(hdsp->card->dev,
51478c2ecf20Sopenharmony_ci				"error creating alsa devices\n");
51488c2ecf20Sopenharmony_ci			return err;
51498c2ecf20Sopenharmony_ci		}
51508c2ecf20Sopenharmony_ci	}
51518c2ecf20Sopenharmony_ci	return 0;
51528c2ecf20Sopenharmony_ci}
51538c2ecf20Sopenharmony_ci
51548c2ecf20Sopenharmony_cistatic int snd_hdsp_create(struct snd_card *card,
51558c2ecf20Sopenharmony_ci			   struct hdsp *hdsp)
51568c2ecf20Sopenharmony_ci{
51578c2ecf20Sopenharmony_ci	struct pci_dev *pci = hdsp->pci;
51588c2ecf20Sopenharmony_ci	int err;
51598c2ecf20Sopenharmony_ci	int is_9652 = 0;
51608c2ecf20Sopenharmony_ci	int is_9632 = 0;
51618c2ecf20Sopenharmony_ci
51628c2ecf20Sopenharmony_ci	hdsp->irq = -1;
51638c2ecf20Sopenharmony_ci	hdsp->state = 0;
51648c2ecf20Sopenharmony_ci	hdsp->midi[0].rmidi = NULL;
51658c2ecf20Sopenharmony_ci	hdsp->midi[1].rmidi = NULL;
51668c2ecf20Sopenharmony_ci	hdsp->midi[0].input = NULL;
51678c2ecf20Sopenharmony_ci	hdsp->midi[1].input = NULL;
51688c2ecf20Sopenharmony_ci	hdsp->midi[0].output = NULL;
51698c2ecf20Sopenharmony_ci	hdsp->midi[1].output = NULL;
51708c2ecf20Sopenharmony_ci	hdsp->midi[0].pending = 0;
51718c2ecf20Sopenharmony_ci	hdsp->midi[1].pending = 0;
51728c2ecf20Sopenharmony_ci	spin_lock_init(&hdsp->midi[0].lock);
51738c2ecf20Sopenharmony_ci	spin_lock_init(&hdsp->midi[1].lock);
51748c2ecf20Sopenharmony_ci	hdsp->iobase = NULL;
51758c2ecf20Sopenharmony_ci	hdsp->control_register = 0;
51768c2ecf20Sopenharmony_ci	hdsp->control2_register = 0;
51778c2ecf20Sopenharmony_ci	hdsp->io_type = Undefined;
51788c2ecf20Sopenharmony_ci	hdsp->max_channels = 26;
51798c2ecf20Sopenharmony_ci
51808c2ecf20Sopenharmony_ci	hdsp->card = card;
51818c2ecf20Sopenharmony_ci
51828c2ecf20Sopenharmony_ci	spin_lock_init(&hdsp->lock);
51838c2ecf20Sopenharmony_ci
51848c2ecf20Sopenharmony_ci	INIT_WORK(&hdsp->midi_work, hdsp_midi_work);
51858c2ecf20Sopenharmony_ci
51868c2ecf20Sopenharmony_ci	pci_read_config_word(hdsp->pci, PCI_CLASS_REVISION, &hdsp->firmware_rev);
51878c2ecf20Sopenharmony_ci	hdsp->firmware_rev &= 0xff;
51888c2ecf20Sopenharmony_ci
51898c2ecf20Sopenharmony_ci	/* From Martin Bjoernsen :
51908c2ecf20Sopenharmony_ci	    "It is important that the card's latency timer register in
51918c2ecf20Sopenharmony_ci	    the PCI configuration space is set to a value much larger
51928c2ecf20Sopenharmony_ci	    than 0 by the computer's BIOS or the driver.
51938c2ecf20Sopenharmony_ci	    The windows driver always sets this 8 bit register [...]
51948c2ecf20Sopenharmony_ci	    to its maximum 255 to avoid problems with some computers."
51958c2ecf20Sopenharmony_ci	*/
51968c2ecf20Sopenharmony_ci	pci_write_config_byte(hdsp->pci, PCI_LATENCY_TIMER, 0xFF);
51978c2ecf20Sopenharmony_ci
51988c2ecf20Sopenharmony_ci	strcpy(card->driver, "H-DSP");
51998c2ecf20Sopenharmony_ci	strcpy(card->mixername, "Xilinx FPGA");
52008c2ecf20Sopenharmony_ci
52018c2ecf20Sopenharmony_ci	if (hdsp->firmware_rev < 0xa)
52028c2ecf20Sopenharmony_ci		return -ENODEV;
52038c2ecf20Sopenharmony_ci	else if (hdsp->firmware_rev < 0x64)
52048c2ecf20Sopenharmony_ci		hdsp->card_name = "RME Hammerfall DSP";
52058c2ecf20Sopenharmony_ci	else if (hdsp->firmware_rev < 0x96) {
52068c2ecf20Sopenharmony_ci		hdsp->card_name = "RME HDSP 9652";
52078c2ecf20Sopenharmony_ci		is_9652 = 1;
52088c2ecf20Sopenharmony_ci	} else {
52098c2ecf20Sopenharmony_ci		hdsp->card_name = "RME HDSP 9632";
52108c2ecf20Sopenharmony_ci		hdsp->max_channels = 16;
52118c2ecf20Sopenharmony_ci		is_9632 = 1;
52128c2ecf20Sopenharmony_ci	}
52138c2ecf20Sopenharmony_ci
52148c2ecf20Sopenharmony_ci	if ((err = pci_enable_device(pci)) < 0)
52158c2ecf20Sopenharmony_ci		return err;
52168c2ecf20Sopenharmony_ci
52178c2ecf20Sopenharmony_ci	pci_set_master(hdsp->pci);
52188c2ecf20Sopenharmony_ci
52198c2ecf20Sopenharmony_ci	if ((err = pci_request_regions(pci, "hdsp")) < 0)
52208c2ecf20Sopenharmony_ci		return err;
52218c2ecf20Sopenharmony_ci	hdsp->port = pci_resource_start(pci, 0);
52228c2ecf20Sopenharmony_ci	if ((hdsp->iobase = ioremap(hdsp->port, HDSP_IO_EXTENT)) == NULL) {
52238c2ecf20Sopenharmony_ci		dev_err(hdsp->card->dev, "unable to remap region 0x%lx-0x%lx\n",
52248c2ecf20Sopenharmony_ci			hdsp->port, hdsp->port + HDSP_IO_EXTENT - 1);
52258c2ecf20Sopenharmony_ci		return -EBUSY;
52268c2ecf20Sopenharmony_ci	}
52278c2ecf20Sopenharmony_ci
52288c2ecf20Sopenharmony_ci	if (request_irq(pci->irq, snd_hdsp_interrupt, IRQF_SHARED,
52298c2ecf20Sopenharmony_ci			KBUILD_MODNAME, hdsp)) {
52308c2ecf20Sopenharmony_ci		dev_err(hdsp->card->dev, "unable to use IRQ %d\n", pci->irq);
52318c2ecf20Sopenharmony_ci		return -EBUSY;
52328c2ecf20Sopenharmony_ci	}
52338c2ecf20Sopenharmony_ci
52348c2ecf20Sopenharmony_ci	hdsp->irq = pci->irq;
52358c2ecf20Sopenharmony_ci	card->sync_irq = hdsp->irq;
52368c2ecf20Sopenharmony_ci	hdsp->precise_ptr = 0;
52378c2ecf20Sopenharmony_ci	hdsp->use_midi_work = 1;
52388c2ecf20Sopenharmony_ci	hdsp->dds_value = 0;
52398c2ecf20Sopenharmony_ci
52408c2ecf20Sopenharmony_ci	if ((err = snd_hdsp_initialize_memory(hdsp)) < 0)
52418c2ecf20Sopenharmony_ci		return err;
52428c2ecf20Sopenharmony_ci
52438c2ecf20Sopenharmony_ci	if (!is_9652 && !is_9632) {
52448c2ecf20Sopenharmony_ci		/* we wait a maximum of 10 seconds to let freshly
52458c2ecf20Sopenharmony_ci		 * inserted cardbus cards do their hardware init */
52468c2ecf20Sopenharmony_ci		err = hdsp_wait_for_iobox(hdsp, 1000, 10);
52478c2ecf20Sopenharmony_ci
52488c2ecf20Sopenharmony_ci		if (err < 0)
52498c2ecf20Sopenharmony_ci			return err;
52508c2ecf20Sopenharmony_ci
52518c2ecf20Sopenharmony_ci		if ((hdsp_read (hdsp, HDSP_statusRegister) & HDSP_DllError) != 0) {
52528c2ecf20Sopenharmony_ci			if ((err = hdsp_request_fw_loader(hdsp)) < 0)
52538c2ecf20Sopenharmony_ci				/* we don't fail as this can happen
52548c2ecf20Sopenharmony_ci				   if userspace is not ready for
52558c2ecf20Sopenharmony_ci				   firmware upload
52568c2ecf20Sopenharmony_ci				*/
52578c2ecf20Sopenharmony_ci				dev_err(hdsp->card->dev,
52588c2ecf20Sopenharmony_ci					"couldn't get firmware from userspace. try using hdsploader\n");
52598c2ecf20Sopenharmony_ci			else
52608c2ecf20Sopenharmony_ci				/* init is complete, we return */
52618c2ecf20Sopenharmony_ci				return 0;
52628c2ecf20Sopenharmony_ci			/* we defer initialization */
52638c2ecf20Sopenharmony_ci			dev_info(hdsp->card->dev,
52648c2ecf20Sopenharmony_ci				 "card initialization pending : waiting for firmware\n");
52658c2ecf20Sopenharmony_ci			if ((err = snd_hdsp_create_hwdep(card, hdsp)) < 0)
52668c2ecf20Sopenharmony_ci				return err;
52678c2ecf20Sopenharmony_ci			return 0;
52688c2ecf20Sopenharmony_ci		} else {
52698c2ecf20Sopenharmony_ci			dev_info(hdsp->card->dev,
52708c2ecf20Sopenharmony_ci				 "Firmware already present, initializing card.\n");
52718c2ecf20Sopenharmony_ci			if (hdsp_read(hdsp, HDSP_status2Register) & HDSP_version2)
52728c2ecf20Sopenharmony_ci				hdsp->io_type = RPM;
52738c2ecf20Sopenharmony_ci			else if (hdsp_read(hdsp, HDSP_status2Register) & HDSP_version1)
52748c2ecf20Sopenharmony_ci				hdsp->io_type = Multiface;
52758c2ecf20Sopenharmony_ci			else
52768c2ecf20Sopenharmony_ci				hdsp->io_type = Digiface;
52778c2ecf20Sopenharmony_ci		}
52788c2ecf20Sopenharmony_ci	}
52798c2ecf20Sopenharmony_ci
52808c2ecf20Sopenharmony_ci	if ((err = snd_hdsp_enable_io(hdsp)) != 0)
52818c2ecf20Sopenharmony_ci		return err;
52828c2ecf20Sopenharmony_ci
52838c2ecf20Sopenharmony_ci	if (is_9652)
52848c2ecf20Sopenharmony_ci	        hdsp->io_type = H9652;
52858c2ecf20Sopenharmony_ci
52868c2ecf20Sopenharmony_ci	if (is_9632)
52878c2ecf20Sopenharmony_ci		hdsp->io_type = H9632;
52888c2ecf20Sopenharmony_ci
52898c2ecf20Sopenharmony_ci	if ((err = snd_hdsp_create_hwdep(card, hdsp)) < 0)
52908c2ecf20Sopenharmony_ci		return err;
52918c2ecf20Sopenharmony_ci
52928c2ecf20Sopenharmony_ci	snd_hdsp_initialize_channels(hdsp);
52938c2ecf20Sopenharmony_ci	snd_hdsp_initialize_midi_flush(hdsp);
52948c2ecf20Sopenharmony_ci
52958c2ecf20Sopenharmony_ci	hdsp->state |= HDSP_FirmwareLoaded;
52968c2ecf20Sopenharmony_ci
52978c2ecf20Sopenharmony_ci	if ((err = snd_hdsp_create_alsa_devices(card, hdsp)) < 0)
52988c2ecf20Sopenharmony_ci		return err;
52998c2ecf20Sopenharmony_ci
53008c2ecf20Sopenharmony_ci	return 0;
53018c2ecf20Sopenharmony_ci}
53028c2ecf20Sopenharmony_ci
53038c2ecf20Sopenharmony_cistatic int snd_hdsp_free(struct hdsp *hdsp)
53048c2ecf20Sopenharmony_ci{
53058c2ecf20Sopenharmony_ci	if (hdsp->port) {
53068c2ecf20Sopenharmony_ci		/* stop the audio, and cancel all interrupts */
53078c2ecf20Sopenharmony_ci		cancel_work_sync(&hdsp->midi_work);
53088c2ecf20Sopenharmony_ci		hdsp->control_register &= ~(HDSP_Start|HDSP_AudioInterruptEnable|HDSP_Midi0InterruptEnable|HDSP_Midi1InterruptEnable);
53098c2ecf20Sopenharmony_ci		hdsp_write (hdsp, HDSP_controlRegister, hdsp->control_register);
53108c2ecf20Sopenharmony_ci	}
53118c2ecf20Sopenharmony_ci
53128c2ecf20Sopenharmony_ci	if (hdsp->irq >= 0)
53138c2ecf20Sopenharmony_ci		free_irq(hdsp->irq, (void *)hdsp);
53148c2ecf20Sopenharmony_ci
53158c2ecf20Sopenharmony_ci	snd_hdsp_free_buffers(hdsp);
53168c2ecf20Sopenharmony_ci
53178c2ecf20Sopenharmony_ci	release_firmware(hdsp->firmware);
53188c2ecf20Sopenharmony_ci	vfree(hdsp->fw_uploaded);
53198c2ecf20Sopenharmony_ci	iounmap(hdsp->iobase);
53208c2ecf20Sopenharmony_ci
53218c2ecf20Sopenharmony_ci	if (hdsp->port)
53228c2ecf20Sopenharmony_ci		pci_release_regions(hdsp->pci);
53238c2ecf20Sopenharmony_ci
53248c2ecf20Sopenharmony_ci	if (pci_is_enabled(hdsp->pci))
53258c2ecf20Sopenharmony_ci		pci_disable_device(hdsp->pci);
53268c2ecf20Sopenharmony_ci	return 0;
53278c2ecf20Sopenharmony_ci}
53288c2ecf20Sopenharmony_ci
53298c2ecf20Sopenharmony_cistatic void snd_hdsp_card_free(struct snd_card *card)
53308c2ecf20Sopenharmony_ci{
53318c2ecf20Sopenharmony_ci	struct hdsp *hdsp = card->private_data;
53328c2ecf20Sopenharmony_ci
53338c2ecf20Sopenharmony_ci	if (hdsp)
53348c2ecf20Sopenharmony_ci		snd_hdsp_free(hdsp);
53358c2ecf20Sopenharmony_ci}
53368c2ecf20Sopenharmony_ci
53378c2ecf20Sopenharmony_cistatic int snd_hdsp_probe(struct pci_dev *pci,
53388c2ecf20Sopenharmony_ci			  const struct pci_device_id *pci_id)
53398c2ecf20Sopenharmony_ci{
53408c2ecf20Sopenharmony_ci	static int dev;
53418c2ecf20Sopenharmony_ci	struct hdsp *hdsp;
53428c2ecf20Sopenharmony_ci	struct snd_card *card;
53438c2ecf20Sopenharmony_ci	int err;
53448c2ecf20Sopenharmony_ci
53458c2ecf20Sopenharmony_ci	if (dev >= SNDRV_CARDS)
53468c2ecf20Sopenharmony_ci		return -ENODEV;
53478c2ecf20Sopenharmony_ci	if (!enable[dev]) {
53488c2ecf20Sopenharmony_ci		dev++;
53498c2ecf20Sopenharmony_ci		return -ENOENT;
53508c2ecf20Sopenharmony_ci	}
53518c2ecf20Sopenharmony_ci
53528c2ecf20Sopenharmony_ci	err = snd_card_new(&pci->dev, index[dev], id[dev], THIS_MODULE,
53538c2ecf20Sopenharmony_ci			   sizeof(struct hdsp), &card);
53548c2ecf20Sopenharmony_ci	if (err < 0)
53558c2ecf20Sopenharmony_ci		return err;
53568c2ecf20Sopenharmony_ci
53578c2ecf20Sopenharmony_ci	hdsp = card->private_data;
53588c2ecf20Sopenharmony_ci	card->private_free = snd_hdsp_card_free;
53598c2ecf20Sopenharmony_ci	hdsp->dev = dev;
53608c2ecf20Sopenharmony_ci	hdsp->pci = pci;
53618c2ecf20Sopenharmony_ci	err = snd_hdsp_create(card, hdsp);
53628c2ecf20Sopenharmony_ci	if (err)
53638c2ecf20Sopenharmony_ci		goto free_card;
53648c2ecf20Sopenharmony_ci
53658c2ecf20Sopenharmony_ci	strcpy(card->shortname, "Hammerfall DSP");
53668c2ecf20Sopenharmony_ci	sprintf(card->longname, "%s at 0x%lx, irq %d", hdsp->card_name,
53678c2ecf20Sopenharmony_ci		hdsp->port, hdsp->irq);
53688c2ecf20Sopenharmony_ci	err = snd_card_register(card);
53698c2ecf20Sopenharmony_ci	if (err) {
53708c2ecf20Sopenharmony_cifree_card:
53718c2ecf20Sopenharmony_ci		snd_card_free(card);
53728c2ecf20Sopenharmony_ci		return err;
53738c2ecf20Sopenharmony_ci	}
53748c2ecf20Sopenharmony_ci	pci_set_drvdata(pci, card);
53758c2ecf20Sopenharmony_ci	dev++;
53768c2ecf20Sopenharmony_ci	return 0;
53778c2ecf20Sopenharmony_ci}
53788c2ecf20Sopenharmony_ci
53798c2ecf20Sopenharmony_cistatic void snd_hdsp_remove(struct pci_dev *pci)
53808c2ecf20Sopenharmony_ci{
53818c2ecf20Sopenharmony_ci	snd_card_free(pci_get_drvdata(pci));
53828c2ecf20Sopenharmony_ci}
53838c2ecf20Sopenharmony_ci
53848c2ecf20Sopenharmony_cistatic struct pci_driver hdsp_driver = {
53858c2ecf20Sopenharmony_ci	.name =     KBUILD_MODNAME,
53868c2ecf20Sopenharmony_ci	.id_table = snd_hdsp_ids,
53878c2ecf20Sopenharmony_ci	.probe =    snd_hdsp_probe,
53888c2ecf20Sopenharmony_ci	.remove = snd_hdsp_remove,
53898c2ecf20Sopenharmony_ci};
53908c2ecf20Sopenharmony_ci
53918c2ecf20Sopenharmony_cimodule_pci_driver(hdsp_driver);
5392