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