--- zzzz-none-000/linux-3.10.107/sound/pci/rme9652/hdspm.c 2017-06-27 09:49:32.000000000 +0000 +++ scorpion-7490-727/linux-3.10.107/sound/pci/rme9652/hdspm.c 2021-02-04 17:41:59.000000000 +0000 @@ -38,6 +38,97 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ + +/* ************* Register Documentation ******************************************************* + * + * Work in progress! Documentation is based on the code in this file. + * + * --------- HDSPM_controlRegister --------- + * :7654.3210:7654.3210:7654.3210:7654.3210: bit number per byte + * :||||.||||:||||.||||:||||.||||:||||.||||: + * :3322.2222:2222.1111:1111.1100:0000.0000: bit number + * :1098.7654:3210.9876:5432.1098:7654.3210: 0..31 + * :||||.||||:||||.||||:||||.||||:||||.||||: + * :8421.8421:8421.8421:8421.8421:8421.8421: hex digit + * : . : . : . : x . : HDSPM_AudioInterruptEnable \_ setting both bits + * : . : . : . : . x: HDSPM_Start / enables audio IO + * : . : . : . : x. : HDSPM_ClockModeMaster - 1: Master, 0: Slave + * : . : . : . : .210 : HDSPM_LatencyMask - 3 Bit value for latency + * : . : . : . : . : 0:64, 1:128, 2:256, 3:512, + * : . : . : . : . : 4:1024, 5:2048, 6:4096, 7:8192 + * :x . : . : . x:xx . : HDSPM_FrequencyMask + * : . : . : . :10 . : HDSPM_Frequency1|HDSPM_Frequency0: 1=32K,2=44.1K,3=48K,0=?? + * : . : . : . x: . : HDSPM_DoubleSpeed + * :x . : . : . : . : HDSPM_QuadSpeed + * : . 3 : . 10: 2 . : . : HDSPM_SyncRefMask : + * : . : . x: . : . : HDSPM_SyncRef0 + * : . : . x : . : . : HDSPM_SyncRef1 + * : . : . : x . : . : HDSPM_SyncRef2 + * : . x : . : . : . : HDSPM_SyncRef3 + * : . : . 10: . : . : sync ref: 0:WC, 1:Madi, 2:TCO, 3:SyncIn + * : . 3 : . 10: 2 . : . : 0:WC, 1:AES1 ... 8:AES8, 9: TCO, 10:SyncIn? + * : . x : . : . : . : HDSPe_FLOAT_FORMAT + * : . : . : x . : . : HDSPM_InputSelect0 : 0=optical,1=coax + * : . : . :x . : . : HDSPM_InputSelect1 + * : . : .x : . : . : HDSPM_clr_tms + * : . : . : . x : . : HDSPM_TX_64ch + * : . : . : . x : . : HDSPM_Emphasis + * : . : . : .x : . : HDSPM_AutoInp + * : . : . x : . : . : HDSPM_SMUX + * : . : .x : . : . : HDSPM_clr_tms + * : . : x. : . : . : HDSPM_taxi_reset + * : . x: . : . : . : HDSPM_LineOut + * : . x: . : . : . : ?????????????????? + * : . : x. : . : . : HDSPM_WCK48 + * : . : . : .x : . : HDSPM_Dolby + * : . : x . : . : . : HDSPM_Midi0InterruptEnable + * : . :x . : . : . : HDSPM_Midi1InterruptEnable + * : . : x . : . : . : HDSPM_Midi2InterruptEnable + * : . x : . : . : . : HDSPM_Midi3InterruptEnable + * : . x : . : . : . : HDSPM_DS_DoubleWire + * : .x : . : . : . : HDSPM_QS_DoubleWire + * : x. : . : . : . : HDSPM_QS_QuadWire + * : . : . : . x : . : HDSPM_Professional + * : x . : . : . : . : HDSPM_wclk_sel + * : . : . : . : . : + * :7654.3210:7654.3210:7654.3210:7654.3210: bit number per byte + * :||||.||||:||||.||||:||||.||||:||||.||||: + * :3322.2222:2222.1111:1111.1100:0000.0000: bit number + * :1098.7654:3210.9876:5432.1098:7654.3210: 0..31 + * :||||.||||:||||.||||:||||.||||:||||.||||: + * :8421.8421:8421.8421:8421.8421:8421.8421:hex digit + * + * + * + * AIO / RayDAT only + * + * ------------ HDSPM_WR_SETTINGS ---------- + * :3322.2222:2222.1111:1111.1100:0000.0000: bit number per byte + * :1098.7654:3210.9876:5432.1098:7654.3210: + * :||||.||||:||||.||||:||||.||||:||||.||||: bit number + * :7654.3210:7654.3210:7654.3210:7654.3210: 0..31 + * :||||.||||:||||.||||:||||.||||:||||.||||: + * :8421.8421:8421.8421:8421.8421:8421.8421: hex digit + * : . : . : . : . x: HDSPM_c0Master 1: Master, 0: Slave + * : . : . : . : . x : HDSPM_c0_SyncRef0 + * : . : . : . : . x : HDSPM_c0_SyncRef1 + * : . : . : . : .x : HDSPM_c0_SyncRef2 + * : . : . : . : x. : HDSPM_c0_SyncRef3 + * : . : . : . : 3.210 : HDSPM_c0_SyncRefMask: + * : . : . : . : . : RayDat: 0:WC, 1:AES, 2:SPDIF, 3..6: ADAT1..4, + * : . : . : . : . : 9:TCO, 10:SyncIn + * : . : . : . : . : AIO: 0:WC, 1:AES, 2: SPDIF, 3: ATAT, + * : . : . : . : . : 9:TCO, 10:SyncIn + * : . : . : . : . : + * : . : . : . : . : + * :3322.2222:2222.1111:1111.1100:0000.0000: bit number per byte + * :1098.7654:3210.9876:5432.1098:7654.3210: + * :||||.||||:||||.||||:||||.||||:||||.||||: bit number + * :7654.3210:7654.3210:7654.3210:7654.3210: 0..31 + * :||||.||||:||||.||||:||||.||||:||||.||||: + * :8421.8421:8421.8421:8421.8421:8421.8421: hex digit + * + */ #include #include #include @@ -45,7 +136,7 @@ #include #include #include -#include +#include #include #include @@ -95,7 +186,7 @@ #define HDSPM_controlRegister 64 #define HDSPM_interruptConfirmation 96 #define HDSPM_control2Reg 256 /* not in specs ???????? */ -#define HDSPM_freqReg 256 /* for AES32 */ +#define HDSPM_freqReg 256 /* for setting arbitrary clock values (DDS feature) */ #define HDSPM_midiDataOut0 352 /* just believe in old code */ #define HDSPM_midiDataOut1 356 #define HDSPM_eeprom_wr 384 /* for AES32 */ @@ -258,6 +349,25 @@ #define HDSPM_wclk_sel (1<<30) +/* additional control register bits for AIO*/ +#define HDSPM_c0_Wck48 0x20 /* also RayDAT */ +#define HDSPM_c0_Input0 0x1000 +#define HDSPM_c0_Input1 0x2000 +#define HDSPM_c0_Spdif_Opt 0x4000 +#define HDSPM_c0_Pro 0x8000 +#define HDSPM_c0_clr_tms 0x10000 +#define HDSPM_c0_AEB1 0x20000 +#define HDSPM_c0_AEB2 0x40000 +#define HDSPM_c0_LineOut 0x80000 +#define HDSPM_c0_AD_GAIN0 0x100000 +#define HDSPM_c0_AD_GAIN1 0x200000 +#define HDSPM_c0_DA_GAIN0 0x400000 +#define HDSPM_c0_DA_GAIN1 0x800000 +#define HDSPM_c0_PH_GAIN0 0x1000000 +#define HDSPM_c0_PH_GAIN1 0x2000000 +#define HDSPM_c0_Sym6db 0x4000000 + + /* --- bit helper defines */ #define HDSPM_LatencyMask (HDSPM_Latency0|HDSPM_Latency1|HDSPM_Latency2) #define HDSPM_FrequencyMask (HDSPM_Frequency0|HDSPM_Frequency1|\ @@ -341,11 +451,11 @@ #define HDSPM_madiLock (1<<3) /* MADI Locked =1, no=0 */ #define HDSPM_madiSync (1<<18) /* MADI is in sync */ -#define HDSPM_tcoLock 0x00000020 /* Optional TCO locked status FOR HDSPe MADI! */ -#define HDSPM_tcoSync 0x10000000 /* Optional TCO sync status */ +#define HDSPM_tcoLockMadi 0x00000020 /* Optional TCO locked status for HDSPe MADI*/ +#define HDSPM_tcoSync 0x10000000 /* Optional TCO sync status for HDSPe MADI and AES32!*/ -#define HDSPM_syncInLock 0x00010000 /* Sync In lock status FOR HDSPe MADI! */ -#define HDSPM_syncInSync 0x00020000 /* Sync In sync status FOR HDSPe MADI! */ +#define HDSPM_syncInLock 0x00010000 /* Sync In lock status for HDSPe MADI! */ +#define HDSPM_syncInSync 0x00020000 /* Sync In sync status for HDSPe MADI! */ #define HDSPM_BufferPositionMask 0x000FFC0 /* Bit 6..15 : h/w buffer pointer */ /* since 64byte accurate, last 6 bits are not used */ @@ -363,7 +473,7 @@ * Interrupt */ #define HDSPM_tco_detect 0x08000000 -#define HDSPM_tco_lock 0x20000000 +#define HDSPM_tcoLockAes 0x20000000 /* Optional TCO locked status for HDSPe AES */ #define HDSPM_s2_tco_detect 0x00000040 #define HDSPM_s2_AEBO_D 0x00000080 @@ -400,8 +510,8 @@ #define HDSPM_wc_freq0 (1<<5) /* input freq detected via autosync */ #define HDSPM_wc_freq1 (1<<6) /* 001=32, 010==44.1, 011=48, */ -#define HDSPM_wc_freq2 (1<<7) /* 100=64, 101=88.2, 110=96, */ -/* missing Bit for 111=128, 1000=176.4, 1001=192 */ +#define HDSPM_wc_freq2 (1<<7) /* 100=64, 101=88.2, 110=96, 111=128 */ +#define HDSPM_wc_freq3 0x800 /* 1000=176.4, 1001=192 */ #define HDSPM_SyncRef0 0x10000 /* Sync Reference */ #define HDSPM_SyncRef1 0x20000 @@ -412,13 +522,17 @@ #define HDSPM_wc_valid (HDSPM_wcLock|HDSPM_wcSync) -#define HDSPM_wcFreqMask (HDSPM_wc_freq0|HDSPM_wc_freq1|HDSPM_wc_freq2) +#define HDSPM_wcFreqMask (HDSPM_wc_freq0|HDSPM_wc_freq1|HDSPM_wc_freq2|\ + HDSPM_wc_freq3) #define HDSPM_wcFreq32 (HDSPM_wc_freq0) #define HDSPM_wcFreq44_1 (HDSPM_wc_freq1) #define HDSPM_wcFreq48 (HDSPM_wc_freq0|HDSPM_wc_freq1) #define HDSPM_wcFreq64 (HDSPM_wc_freq2) #define HDSPM_wcFreq88_2 (HDSPM_wc_freq0|HDSPM_wc_freq2) #define HDSPM_wcFreq96 (HDSPM_wc_freq1|HDSPM_wc_freq2) +#define HDSPM_wcFreq128 (HDSPM_wc_freq0|HDSPM_wc_freq1|HDSPM_wc_freq2) +#define HDSPM_wcFreq176_4 (HDSPM_wc_freq3) +#define HDSPM_wcFreq192 (HDSPM_wc_freq0|HDSPM_wc_freq3) #define HDSPM_status1_F_0 0x0400000 #define HDSPM_status1_F_1 0x0800000 @@ -457,7 +571,9 @@ #define HDSPM_AES32_AUTOSYNC_FROM_AES6 6 #define HDSPM_AES32_AUTOSYNC_FROM_AES7 7 #define HDSPM_AES32_AUTOSYNC_FROM_AES8 8 -#define HDSPM_AES32_AUTOSYNC_FROM_NONE 9 +#define HDSPM_AES32_AUTOSYNC_FROM_TCO 9 +#define HDSPM_AES32_AUTOSYNC_FROM_SYNC_IN 10 +#define HDSPM_AES32_AUTOSYNC_FROM_NONE 11 /* status2 */ /* HDSPM_LockAES_bit is given by HDSPM_LockAES >> (AES# - 1) */ @@ -533,36 +649,39 @@ /* names for speed modes */ static char *hdspm_speed_names[] = { "single", "double", "quad" }; -static char *texts_autosync_aes_tco[] = { "Word Clock", +static const char *const texts_autosync_aes_tco[] = { "Word Clock", "AES1", "AES2", "AES3", "AES4", "AES5", "AES6", "AES7", "AES8", - "TCO" }; -static char *texts_autosync_aes[] = { "Word Clock", + "TCO", "Sync In" +}; +static const char *const texts_autosync_aes[] = { "Word Clock", "AES1", "AES2", "AES3", "AES4", - "AES5", "AES6", "AES7", "AES8" }; -static char *texts_autosync_madi_tco[] = { "Word Clock", + "AES5", "AES6", "AES7", "AES8", + "Sync In" +}; +static const char *const texts_autosync_madi_tco[] = { "Word Clock", "MADI", "TCO", "Sync In" }; -static char *texts_autosync_madi[] = { "Word Clock", +static const char *const texts_autosync_madi[] = { "Word Clock", "MADI", "Sync In" }; -static char *texts_autosync_raydat_tco[] = { +static const char *const texts_autosync_raydat_tco[] = { "Word Clock", "ADAT 1", "ADAT 2", "ADAT 3", "ADAT 4", "AES", "SPDIF", "TCO", "Sync In" }; -static char *texts_autosync_raydat[] = { +static const char *const texts_autosync_raydat[] = { "Word Clock", "ADAT 1", "ADAT 2", "ADAT 3", "ADAT 4", "AES", "SPDIF", "Sync In" }; -static char *texts_autosync_aio_tco[] = { +static const char *const texts_autosync_aio_tco[] = { "Word Clock", "ADAT", "AES", "SPDIF", "TCO", "Sync In" }; -static char *texts_autosync_aio[] = { "Word Clock", +static const char *const texts_autosync_aio[] = { "Word Clock", "ADAT", "AES", "SPDIF", "Sync In" }; -static char *texts_freq[] = { +static const char *const texts_freq[] = { "No Lock", "32 kHz", "44.1 kHz", @@ -625,7 +744,8 @@ "AES.L", "AES.R", "SPDIF.L", "SPDIF.R", "ADAT.1", "ADAT.2", "ADAT.3", "ADAT.4", "ADAT.5", "ADAT.6", - "ADAT.7", "ADAT.8" + "ADAT.7", "ADAT.8", + "AEB.1", "AEB.2", "AEB.3", "AEB.4" }; static char *texts_ports_aio_out_ss[] = { @@ -634,14 +754,16 @@ "SPDIF.L", "SPDIF.R", "ADAT.1", "ADAT.2", "ADAT.3", "ADAT.4", "ADAT.5", "ADAT.6", "ADAT.7", "ADAT.8", - "Phone.L", "Phone.R" + "Phone.L", "Phone.R", + "AEB.1", "AEB.2", "AEB.3", "AEB.4" }; static char *texts_ports_aio_in_ds[] = { "Analogue.L", "Analogue.R", "AES.L", "AES.R", "SPDIF.L", "SPDIF.R", - "ADAT.1", "ADAT.2", "ADAT.3", "ADAT.4" + "ADAT.1", "ADAT.2", "ADAT.3", "ADAT.4", + "AEB.1", "AEB.2", "AEB.3", "AEB.4" }; static char *texts_ports_aio_out_ds[] = { @@ -649,14 +771,16 @@ "AES.L", "AES.R", "SPDIF.L", "SPDIF.R", "ADAT.1", "ADAT.2", "ADAT.3", "ADAT.4", - "Phone.L", "Phone.R" + "Phone.L", "Phone.R", + "AEB.1", "AEB.2", "AEB.3", "AEB.4" }; static char *texts_ports_aio_in_qs[] = { "Analogue.L", "Analogue.R", "AES.L", "AES.R", "SPDIF.L", "SPDIF.R", - "ADAT.1", "ADAT.2", "ADAT.3", "ADAT.4" + "ADAT.1", "ADAT.2", "ADAT.3", "ADAT.4", + "AEB.1", "AEB.2", "AEB.3", "AEB.4" }; static char *texts_ports_aio_out_qs[] = { @@ -664,7 +788,8 @@ "AES.L", "AES.R", "SPDIF.L", "SPDIF.R", "ADAT.1", "ADAT.2", "ADAT.3", "ADAT.4", - "Phone.L", "Phone.R" + "Phone.L", "Phone.R", + "AEB.1", "AEB.2", "AEB.3", "AEB.4" }; static char *texts_ports_aes32[] = { @@ -741,8 +866,8 @@ 8, 9, /* aes in, */ 10, 11, /* spdif in */ 12, 13, 14, 15, 16, 17, 18, 19, /* ADAT in */ - -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, + 2, 3, 4, 5, /* AEB */ + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, @@ -756,7 +881,8 @@ 10, 11, /* spdif out */ 12, 13, 14, 15, 16, 17, 18, 19, /* ADAT out */ 6, 7, /* phone out */ - -1, -1, -1, -1, -1, -1, -1, -1, + 2, 3, 4, 5, /* AEB */ + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, @@ -769,7 +895,8 @@ 8, 9, /* aes in */ 10, 11, /* spdif in */ 12, 14, 16, 18, /* adat in */ - -1, -1, -1, -1, -1, -1, + 2, 3, 4, 5, /* AEB */ + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, @@ -784,7 +911,7 @@ 10, 11, /* spdif out */ 12, 14, 16, 18, /* adat out */ 6, 7, /* phone out */ - -1, -1, -1, -1, + 2, 3, 4, 5, /* AEB */ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, @@ -798,7 +925,8 @@ 8, 9, /* aes in */ 10, 11, /* spdif in */ 12, 16, /* adat in */ - -1, -1, -1, -1, -1, -1, -1, -1, + 2, 3, 4, 5, /* AEB */ + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, @@ -813,7 +941,8 @@ 10, 11, /* spdif out */ 12, 16, /* adat out */ 6, 7, /* phone out */ - -1, -1, -1, -1, -1, -1, + 2, 3, 4, 5, /* AEB */ + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, @@ -852,11 +981,11 @@ }; struct hdspm_tco { - int input; - int framerate; - int wordclock; - int samplerate; - int pull; + int input; /* 0: LTC, 1:Video, 2: WC*/ + int framerate; /* 0=24, 1=25, 2=29.97, 3=29.97d, 4=30, 5=30d */ + int wordclock; /* 0=1:1, 1=44.1->48, 2=48->44.1 */ + int samplerate; /* 0=44.1, 1=48, 2= freq from app */ + int pull; /* 0=0, 1=+0.1%, 2=-0.1%, 3=+4%, 4=-4%*/ int term; /* 0 = off, 1 = on */ }; @@ -875,7 +1004,7 @@ u32 control_register; /* cached value */ u32 control2_register; /* cached value */ - u32 settings_register; + u32 settings_register; /* cached value for AIO / RayDat (sync reference, master/slave) */ struct hdspm_midi midi[4]; struct tasklet_struct midi_tasklet; @@ -937,7 +1066,7 @@ struct hdspm_tco *tco; /* NULL if no TCO detected */ - char **texts_autosync; + const char *const *texts_autosync; int texts_autosync_items; cycles_t last_interrupt; @@ -948,7 +1077,7 @@ }; -static DEFINE_PCI_DEVICE_TABLE(snd_hdspm_ids) = { +static const struct pci_device_id snd_hdspm_ids[] = { { .vendor = PCI_VENDOR_ID_XILINX, .device = PCI_DEVICE_ID_XILINX_HAMMERFALL_DSP_MADI, @@ -972,12 +1101,24 @@ static inline int hdspm_get_pll_freq(struct hdspm *hdspm); static int hdspm_update_simple_mixer_controls(struct hdspm *hdspm); static int hdspm_autosync_ref(struct hdspm *hdspm); +static int hdspm_set_toggle_setting(struct hdspm *hdspm, u32 regmask, int out); static int snd_hdspm_set_defaults(struct hdspm *hdspm); static int hdspm_system_clock_mode(struct hdspm *hdspm); static void hdspm_set_sgbuf(struct hdspm *hdspm, struct snd_pcm_substream *substream, unsigned int reg, int channels); +static int hdspm_aes_sync_check(struct hdspm *hdspm, int idx); +static int hdspm_wc_sync_check(struct hdspm *hdspm); +static int hdspm_tco_sync_check(struct hdspm *hdspm); +static int hdspm_sync_in_sync_check(struct hdspm *hdspm); + +static int hdspm_get_aes_sample_rate(struct hdspm *hdspm, int index); +static int hdspm_get_tco_sample_rate(struct hdspm *hdspm); +static int hdspm_get_wc_sample_rate(struct hdspm *hdspm); + + + static inline int HDSPM_bit2freq(int n) { static const int bit2freq_tab[] = { @@ -988,6 +1129,12 @@ return bit2freq_tab[n]; } +static bool hdspm_is_raydat_or_aio(struct hdspm *hdspm) +{ + return ((AIO == hdspm->io_type) || (RayDAT == hdspm->io_type)); +} + + /* Write/read to/from HDSPM with Adresses in Bytes not words but only 32Bit writes are allowed */ @@ -1087,33 +1234,68 @@ return 48000; } -static int hdspm_tco_sync_check(struct hdspm *hdspm); -static int hdspm_sync_in_sync_check(struct hdspm *hdspm); +/* QS and DS rates normally can not be detected + * automatically by the card. Only exception is MADI + * in 96k frame mode. + * + * So if we read SS values (32 .. 48k), check for + * user-provided DS/QS bits in the control register + * and multiply the base frequency accordingly. + */ +static int hdspm_rate_multiplier(struct hdspm *hdspm, int rate) +{ + if (rate <= 48000) { + if (hdspm->control_register & HDSPM_QuadSpeed) + return rate * 4; + else if (hdspm->control_register & + HDSPM_DoubleSpeed) + return rate * 2; + } + return rate; +} -/* check for external sample rate */ +/* check for external sample rate, returns the sample rate in Hz*/ static int hdspm_external_sample_rate(struct hdspm *hdspm) { - unsigned int status, status2, timecode; + unsigned int status, status2; int syncref, rate = 0, rate_bits; switch (hdspm->io_type) { case AES32: status2 = hdspm_read(hdspm, HDSPM_statusRegister2); status = hdspm_read(hdspm, HDSPM_statusRegister); - timecode = hdspm_read(hdspm, HDSPM_timecodeRegister); syncref = hdspm_autosync_ref(hdspm); + switch (syncref) { + case HDSPM_AES32_AUTOSYNC_FROM_WORD: + /* Check WC sync and get sample rate */ + if (hdspm_wc_sync_check(hdspm)) + return HDSPM_bit2freq(hdspm_get_wc_sample_rate(hdspm)); + break; + + case HDSPM_AES32_AUTOSYNC_FROM_AES1: + case HDSPM_AES32_AUTOSYNC_FROM_AES2: + case HDSPM_AES32_AUTOSYNC_FROM_AES3: + case HDSPM_AES32_AUTOSYNC_FROM_AES4: + case HDSPM_AES32_AUTOSYNC_FROM_AES5: + case HDSPM_AES32_AUTOSYNC_FROM_AES6: + case HDSPM_AES32_AUTOSYNC_FROM_AES7: + case HDSPM_AES32_AUTOSYNC_FROM_AES8: + /* Check AES sync and get sample rate */ + if (hdspm_aes_sync_check(hdspm, syncref - HDSPM_AES32_AUTOSYNC_FROM_AES1)) + return HDSPM_bit2freq(hdspm_get_aes_sample_rate(hdspm, + syncref - HDSPM_AES32_AUTOSYNC_FROM_AES1)); + break; - if (syncref == HDSPM_AES32_AUTOSYNC_FROM_WORD && - status & HDSPM_AES32_wcLock) - return HDSPM_bit2freq((status >> HDSPM_AES32_wcFreq_bit) & 0xF); - - if (syncref >= HDSPM_AES32_AUTOSYNC_FROM_AES1 && - syncref <= HDSPM_AES32_AUTOSYNC_FROM_AES8 && - status2 & (HDSPM_LockAES >> - (syncref - HDSPM_AES32_AUTOSYNC_FROM_AES1))) - return HDSPM_bit2freq((timecode >> (4*(syncref-HDSPM_AES32_AUTOSYNC_FROM_AES1))) & 0xF); - return 0; + + case HDSPM_AES32_AUTOSYNC_FROM_TCO: + /* Check TCO sync and get sample rate */ + if (hdspm_tco_sync_check(hdspm)) + return HDSPM_bit2freq(hdspm_get_tco_sample_rate(hdspm)); + break; + default: + return 0; + } /* end switch(syncref) */ break; case MADIface: @@ -1181,6 +1363,15 @@ case HDSPM_wcFreq96: rate = 96000; break; + case HDSPM_wcFreq128: + rate = 128000; + break; + case HDSPM_wcFreq176_4: + rate = 176400; + break; + case HDSPM_wcFreq192: + rate = 192000; + break; default: rate = 0; break; @@ -1192,7 +1383,7 @@ */ if (rate != 0 && (status2 & HDSPM_SelSyncRefMask) == HDSPM_SelSyncRef_WORD) - return rate; + return hdspm_rate_multiplier(hdspm, rate); /* maybe a madi input (which is taken if sel sync is madi) */ if (status & HDSPM_madiLock) { @@ -1255,21 +1446,8 @@ } } - /* QS and DS rates normally can not be detected - * automatically by the card. Only exception is MADI - * in 96k frame mode. - * - * So if we read SS values (32 .. 48k), check for - * user-provided DS/QS bits in the control register - * and multiply the base frequency accordingly. - */ - if (rate <= 48000) { - if (hdspm->control_register & HDSPM_QuadSpeed) - rate *= 4; - else if (hdspm->control_register & - HDSPM_DoubleSpeed) - rate *= 2; - } + rate = hdspm_rate_multiplier(hdspm, rate); + break; } @@ -1475,9 +1653,8 @@ just make a warning an remember setting for future master mode switching */ - snd_printk(KERN_WARNING "HDSPM: " - "Warning: device is not running " - "as a clock master.\n"); + dev_warn(hdspm->card->dev, + "Warning: device is not running as a clock master.\n"); not_set = 1; } else { @@ -1488,15 +1665,14 @@ if (hdspm_autosync_ref(hdspm) == HDSPM_AUTOSYNC_FROM_NONE) { - snd_printk(KERN_WARNING "HDSPM: " - "Detected no Externel Sync \n"); + dev_warn(hdspm->card->dev, + "Detected no Externel Sync\n"); not_set = 1; } else if (rate != external_freq) { - snd_printk(KERN_WARNING "HDSPM: " - "Warning: No AutoSync source for " - "requested rate\n"); + dev_warn(hdspm->card->dev, + "Warning: No AutoSync source for requested rate\n"); not_set = 1; } } @@ -1562,13 +1738,11 @@ if (current_speed != target_speed && (hdspm->capture_pid >= 0 || hdspm->playback_pid >= 0)) { - snd_printk - (KERN_ERR "HDSPM: " - "cannot change from %s speed to %s speed mode " - "(capture PID = %d, playback PID = %d)\n", - hdspm_speed_names[current_speed], - hdspm_speed_names[target_speed], - hdspm->capture_pid, hdspm->playback_pid); + dev_err(hdspm->card->dev, + "cannot change from %s speed to %s speed mode (capture PID = %d, playback PID = %d)\n", + hdspm_speed_names[current_speed], + hdspm_speed_names[target_speed], + hdspm->capture_pid, hdspm->playback_pid); return -EBUSY; } @@ -1786,10 +1960,8 @@ leaving istimer wherever it was set before. */ - if (hmidi->istimer) { - hmidi->timer.expires = 1 + jiffies; - add_timer(&hmidi->timer); - } + if (hmidi->istimer) + mod_timer(&hmidi->timer, 1 + jiffies); spin_unlock_irqrestore (&hmidi->lock, flags); } @@ -1804,11 +1976,9 @@ spin_lock_irqsave (&hmidi->lock, flags); if (up) { if (!hmidi->istimer) { - init_timer(&hmidi->timer); - hmidi->timer.function = snd_hdspm_midi_output_timer; - hmidi->timer.data = (unsigned long) hmidi; - hmidi->timer.expires = 1 + jiffies; - add_timer(&hmidi->timer); + setup_timer(&hmidi->timer, snd_hdspm_midi_output_timer, + (unsigned long) hmidi); + mod_timer(&hmidi->timer, 1 + jiffies); hmidi->istimer++; } } else { @@ -2030,10 +2200,10 @@ return rate; } -/** +/* * Calculate the real sample rate from the * current DDS value. - **/ + */ static int hdspm_get_system_sample_rate(struct hdspm *hdspm) { unsigned int rate; @@ -2104,9 +2274,9 @@ } -/** +/* * Returns the WordClock sample rate class for the given card. - **/ + */ static int hdspm_get_wc_sample_rate(struct hdspm *hdspm) { int status; @@ -2117,6 +2287,9 @@ status = hdspm_read(hdspm, HDSPM_RD_STATUS_1); return (status >> 16) & 0xF; break; + case AES32: + status = hdspm_read(hdspm, HDSPM_statusRegister); + return (status >> HDSPM_AES32_wcFreq_bit) & 0xF; default: break; } @@ -2126,9 +2299,9 @@ } -/** +/* * Returns the TCO sample rate class for the given card. - **/ + */ static int hdspm_get_tco_sample_rate(struct hdspm *hdspm) { int status; @@ -2140,6 +2313,9 @@ status = hdspm_read(hdspm, HDSPM_RD_STATUS_1); return (status >> 20) & 0xF; break; + case AES32: + status = hdspm_read(hdspm, HDSPM_statusRegister); + return (status >> 1) & 0xF; default: break; } @@ -2149,9 +2325,9 @@ } -/** +/* * Returns the SYNC_IN sample rate class for the given card. - **/ + */ static int hdspm_get_sync_in_sample_rate(struct hdspm *hdspm) { int status; @@ -2171,11 +2347,28 @@ return 0; } +/* + * Returns the AES sample rate class for the given card. + */ +static int hdspm_get_aes_sample_rate(struct hdspm *hdspm, int index) +{ + int timecode; -/** + switch (hdspm->io_type) { + case AES32: + timecode = hdspm_read(hdspm, HDSPM_timecodeRegister); + return (timecode >> (4*index)) & 0xF; + break; + default: + break; + } + return 0; +} + +/* * Returns the sample rate class for input source for * 'new style' cards like the AIO and RayDAT. - **/ + */ static int hdspm_get_s1_sample_rate(struct hdspm *hdspm, unsigned int idx) { int status = hdspm_read(hdspm, HDSPM_RD_STATUS_2); @@ -2184,15 +2377,23 @@ } #define ENUMERATED_CTL_INFO(info, texts) \ -{ \ - uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; \ - uinfo->count = 1; \ - uinfo->value.enumerated.items = ARRAY_SIZE(texts); \ - if (uinfo->value.enumerated.item >= uinfo->value.enumerated.items) \ - uinfo->value.enumerated.item = uinfo->value.enumerated.items - 1; \ - strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]); \ -} + snd_ctl_enum_info(info, 1, ARRAY_SIZE(texts), texts) + +/* Helper function to query the external sample rate and return the + * corresponding enum to be returned to userspace. + */ +static int hdspm_external_rate_to_enum(struct hdspm *hdspm) +{ + int rate = hdspm_external_sample_rate(hdspm); + int i, selected_rate = 0; + for (i = 1; i < 10; i++) + if (HDSPM_bit2freq(i) == rate) { + selected_rate = i; + break; + } + return selected_rate; +} #define HDSPM_AUTOSYNC_SAMPLE_RATE(xname, xindex) \ @@ -2258,7 +2459,7 @@ default: ucontrol->value.enumerated.item[0] = hdspm_get_s1_sample_rate(hdspm, - ucontrol->id.index-1); + kcontrol->private_value-1); } break; @@ -2277,28 +2478,24 @@ ucontrol->value.enumerated.item[0] = hdspm_get_sync_in_sample_rate(hdspm); break; + case 11: /* External Rate */ + ucontrol->value.enumerated.item[0] = + hdspm_external_rate_to_enum(hdspm); + break; default: /* AES1 to AES8 */ ucontrol->value.enumerated.item[0] = - hdspm_get_s1_sample_rate(hdspm, - kcontrol->private_value-1); + hdspm_get_aes_sample_rate(hdspm, + kcontrol->private_value - + HDSPM_AES32_AUTOSYNC_FROM_AES1); break; } break; case MADI: case MADIface: - { - int rate = hdspm_external_sample_rate(hdspm); - int i, selected_rate = 0; - for (i = 1; i < 10; i++) - if (HDSPM_bit2freq(i) == rate) { - selected_rate = i; - break; - } - ucontrol->value.enumerated.item[0] = selected_rate; - } + ucontrol->value.enumerated.item[0] = + hdspm_external_rate_to_enum(hdspm); break; - default: break; } @@ -2319,10 +2516,10 @@ } -/** +/* * Returns the system clock mode for the given card. * @returns 0 - master, 1 - slave - **/ + */ static int hdspm_system_clock_mode(struct hdspm *hdspm) { switch (hdspm->io_type) { @@ -2341,39 +2538,23 @@ } -/** +/* * Sets the system clock mode. * @param mode 0 - master, 1 - slave - **/ + */ static void hdspm_set_system_clock_mode(struct hdspm *hdspm, int mode) { - switch (hdspm->io_type) { - case AIO: - case RayDAT: - if (0 == mode) - hdspm->settings_register |= HDSPM_c0Master; - else - hdspm->settings_register &= ~HDSPM_c0Master; - - hdspm_write(hdspm, HDSPM_WR_SETTINGS, hdspm->settings_register); - break; - - default: - if (0 == mode) - hdspm->control_register |= HDSPM_ClockModeMaster; - else - hdspm->control_register &= ~HDSPM_ClockModeMaster; - - hdspm_write(hdspm, HDSPM_controlRegister, - hdspm->control_register); - } + hdspm_set_toggle_setting(hdspm, + (hdspm_is_raydat_or_aio(hdspm)) ? + HDSPM_c0Master : HDSPM_ClockModeMaster, + (0 == mode)); } static int snd_hdspm_info_system_clock_mode(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) { - static char *texts[] = { "Master", "AutoSync" }; + static const char *const texts[] = { "Master", "AutoSync" }; ENUMERATED_CTL_INFO(uinfo, texts); return 0; } @@ -2467,18 +2648,7 @@ static int snd_hdspm_info_clock_source(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) { - uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; - uinfo->count = 1; - uinfo->value.enumerated.items = 9; - - if (uinfo->value.enumerated.item >= uinfo->value.enumerated.items) - uinfo->value.enumerated.item = - uinfo->value.enumerated.items - 1; - - strcpy(uinfo->value.enumerated.name, - texts_freq[uinfo->value.enumerated.item+1]); - - return 0; + return snd_ctl_enum_info(uinfo, 1, 9, texts_freq + 1); } static int snd_hdspm_get_clock_source(struct snd_kcontrol *kcontrol, @@ -2526,11 +2696,11 @@ } -/** +/* * Returns the current preferred sync reference setting. * The semantics of the return value are depending on the * card, please see the comments for clarification. - **/ + */ static int hdspm_pref_sync_ref(struct hdspm * hdspm) { switch (hdspm->io_type) { @@ -2629,11 +2799,11 @@ } -/** +/* * Set the preferred sync reference to . The semantics * of are depending on the card type, see the comments * for clarification. - **/ + */ static int hdspm_set_pref_sync_ref(struct hdspm * hdspm, int pref) { int p = 0; @@ -2797,16 +2967,7 @@ { struct hdspm *hdspm = snd_kcontrol_chip(kcontrol); - uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; - uinfo->count = 1; - uinfo->value.enumerated.items = hdspm->texts_autosync_items; - - if (uinfo->value.enumerated.item >= uinfo->value.enumerated.items) - uinfo->value.enumerated.item = - uinfo->value.enumerated.items - 1; - - strcpy(uinfo->value.enumerated.name, - hdspm->texts_autosync[uinfo->value.enumerated.item]); + snd_ctl_enum_info(uinfo, 1, hdspm->texts_autosync_items, hdspm->texts_autosync); return 0; } @@ -2861,19 +3022,20 @@ static int hdspm_autosync_ref(struct hdspm *hdspm) { + /* This looks at the autosync selected sync reference */ if (AES32 == hdspm->io_type) { + unsigned int status = hdspm_read(hdspm, HDSPM_statusRegister); - unsigned int syncref = - (status >> HDSPM_AES32_syncref_bit) & 0xF; - if (syncref == 0) - return HDSPM_AES32_AUTOSYNC_FROM_WORD; - if (syncref <= 8) + unsigned int syncref = (status >> HDSPM_AES32_syncref_bit) & 0xF; + if ((syncref >= HDSPM_AES32_AUTOSYNC_FROM_WORD) && + (syncref <= HDSPM_AES32_AUTOSYNC_FROM_SYNC_IN)) { return syncref; + } return HDSPM_AES32_AUTOSYNC_FROM_NONE; + } else if (MADI == hdspm->io_type) { - /* This looks at the autosync selected sync reference */ - unsigned int status2 = hdspm_read(hdspm, HDSPM_statusRegister2); + unsigned int status2 = hdspm_read(hdspm, HDSPM_statusRegister2); switch (status2 & HDSPM_SelSyncRefMask) { case HDSPM_SelSyncRef_WORD: return HDSPM_AUTOSYNC_FROM_WORD; @@ -2886,7 +3048,7 @@ case HDSPM_SelSyncRef_NVALID: return HDSPM_AUTOSYNC_FROM_NONE; default: - return 0; + return HDSPM_AUTOSYNC_FROM_NONE; } } @@ -2900,31 +3062,15 @@ struct hdspm *hdspm = snd_kcontrol_chip(kcontrol); if (AES32 == hdspm->io_type) { - static char *texts[] = { "WordClock", "AES1", "AES2", "AES3", - "AES4", "AES5", "AES6", "AES7", "AES8", "None"}; + static const char *const texts[] = { "WordClock", "AES1", "AES2", "AES3", + "AES4", "AES5", "AES6", "AES7", "AES8", "TCO", "Sync In", "None"}; - uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; - uinfo->count = 1; - uinfo->value.enumerated.items = 10; - if (uinfo->value.enumerated.item >= - uinfo->value.enumerated.items) - uinfo->value.enumerated.item = - uinfo->value.enumerated.items - 1; - strcpy(uinfo->value.enumerated.name, - texts[uinfo->value.enumerated.item]); + ENUMERATED_CTL_INFO(uinfo, texts); } else if (MADI == hdspm->io_type) { - static char *texts[] = {"Word Clock", "MADI", "TCO", + static const char *const texts[] = {"Word Clock", "MADI", "TCO", "Sync In", "None" }; - uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; - uinfo->count = 1; - uinfo->value.enumerated.items = 5; - if (uinfo->value.enumerated.item >= - uinfo->value.enumerated.items) - uinfo->value.enumerated.item = - uinfo->value.enumerated.items - 1; - strcpy(uinfo->value.enumerated.name, - texts[uinfo->value.enumerated.item]); + ENUMERATED_CTL_INFO(uinfo, texts); } return 0; } @@ -2952,7 +3098,7 @@ static int snd_hdspm_info_tco_video_input_format(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) { - static char *texts[] = {"No video", "NTSC", "PAL"}; + static const char *const texts[] = {"No video", "NTSC", "PAL"}; ENUMERATED_CTL_INFO(uinfo, texts); return 0; } @@ -2998,7 +3144,7 @@ static int snd_hdspm_info_tco_ltc_frames(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) { - static char *texts[] = {"No lock", "24 fps", "25 fps", "29.97 fps", + static const char *const texts[] = {"No lock", "24 fps", "25 fps", "29.97 fps", "30 fps"}; ENUMERATED_CTL_INFO(uinfo, texts); return 0; @@ -3015,19 +3161,19 @@ HDSPM_TCO1_LTC_Format_MSB)) { case 0: /* 24 fps */ - ret = 1; + ret = fps_24; break; case HDSPM_TCO1_LTC_Format_LSB: /* 25 fps */ - ret = 2; + ret = fps_25; break; case HDSPM_TCO1_LTC_Format_MSB: - /* 25 fps */ - ret = 3; + /* 29.97 fps */ + ret = fps_2997; break; default: /* 30 fps */ - ret = 4; + ret = fps_30; break; } } @@ -3055,16 +3201,35 @@ static int hdspm_toggle_setting(struct hdspm *hdspm, u32 regmask) { - return (hdspm->control_register & regmask) ? 1 : 0; + u32 reg; + + if (hdspm_is_raydat_or_aio(hdspm)) + reg = hdspm->settings_register; + else + reg = hdspm->control_register; + + return (reg & regmask) ? 1 : 0; } static int hdspm_set_toggle_setting(struct hdspm *hdspm, u32 regmask, int out) { + u32 *reg; + u32 target_reg; + + if (hdspm_is_raydat_or_aio(hdspm)) { + reg = &(hdspm->settings_register); + target_reg = HDSPM_WR_SETTINGS; + } else { + reg = &(hdspm->control_register); + target_reg = HDSPM_controlRegister; + } + if (out) - hdspm->control_register |= regmask; + *reg |= regmask; else - hdspm->control_register &= ~regmask; - hdspm_write(hdspm, HDSPM_controlRegister, hdspm->control_register); + *reg &= ~regmask; + + hdspm_write(hdspm, target_reg, *reg); return 0; } @@ -3129,7 +3294,7 @@ static int snd_hdspm_info_input_select(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) { - static char *texts[] = { "optical", "coaxial" }; + static const char *const texts[] = { "optical", "coaxial" }; ENUMERATED_CTL_INFO(uinfo, texts); return 0; } @@ -3191,7 +3356,7 @@ static int snd_hdspm_info_ds_wire(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) { - static char *texts[] = { "Single", "Double" }; + static const char *const texts[] = { "Single", "Double" }; ENUMERATED_CTL_INFO(uinfo, texts); return 0; } @@ -3264,7 +3429,7 @@ static int snd_hdspm_info_qs_wire(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) { - static char *texts[] = { "Single", "Double", "Quad" }; + static const char *const texts[] = { "Single", "Double", "Quad" }; ENUMERATED_CTL_INFO(uinfo, texts); return 0; } @@ -3301,6 +3466,84 @@ return change; } +#define HDSPM_CONTROL_TRISTATE(xname, xindex) \ +{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \ + .name = xname, \ + .private_value = xindex, \ + .info = snd_hdspm_info_tristate, \ + .get = snd_hdspm_get_tristate, \ + .put = snd_hdspm_put_tristate \ +} + +static int hdspm_tristate(struct hdspm *hdspm, u32 regmask) +{ + u32 reg = hdspm->settings_register & (regmask * 3); + return reg / regmask; +} + +static int hdspm_set_tristate(struct hdspm *hdspm, int mode, u32 regmask) +{ + hdspm->settings_register &= ~(regmask * 3); + hdspm->settings_register |= (regmask * mode); + hdspm_write(hdspm, HDSPM_WR_SETTINGS, hdspm->settings_register); + + return 0; +} + +static int snd_hdspm_info_tristate(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_info *uinfo) +{ + u32 regmask = kcontrol->private_value; + + static const char *const texts_spdif[] = { "Optical", "Coaxial", "Internal" }; + static const char *const texts_levels[] = { "Hi Gain", "+4 dBu", "-10 dBV" }; + + switch (regmask) { + case HDSPM_c0_Input0: + ENUMERATED_CTL_INFO(uinfo, texts_spdif); + break; + default: + ENUMERATED_CTL_INFO(uinfo, texts_levels); + break; + } + return 0; +} + +static int snd_hdspm_get_tristate(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct hdspm *hdspm = snd_kcontrol_chip(kcontrol); + u32 regmask = kcontrol->private_value; + + spin_lock_irq(&hdspm->lock); + ucontrol->value.enumerated.item[0] = hdspm_tristate(hdspm, regmask); + spin_unlock_irq(&hdspm->lock); + return 0; +} + +static int snd_hdspm_put_tristate(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct hdspm *hdspm = snd_kcontrol_chip(kcontrol); + u32 regmask = kcontrol->private_value; + int change; + int val; + + if (!snd_hdspm_use_is_exclusive(hdspm)) + return -EBUSY; + val = ucontrol->value.integer.value[0]; + if (val < 0) + val = 0; + if (val > 2) + val = 2; + + spin_lock_irq(&hdspm->lock); + change = val != hdspm_tristate(hdspm, regmask); + hdspm_set_tristate(hdspm, val, regmask); + spin_unlock_irq(&hdspm->lock); + return change; +} + #define HDSPM_MADI_SPEEDMODE(xname, xindex) \ { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \ .name = xname, \ @@ -3340,7 +3583,7 @@ static int snd_hdspm_info_madi_speedmode(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) { - static char *texts[] = { "Single", "Double", "Quad" }; + static const char *const texts[] = { "Single", "Double", "Quad" }; ENUMERATED_CTL_INFO(uinfo, texts); return 0; } @@ -3575,7 +3818,7 @@ static int snd_hdspm_info_sync_check(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) { - static char *texts[] = { "No Lock", "Lock", "Sync", "N/A" }; + static const char *const texts[] = { "No Lock", "Lock", "Sync", "N/A" }; ENUMERATED_CTL_INFO(uinfo, texts); return 0; } @@ -3583,7 +3826,7 @@ static int snd_hdspm_tco_info_lock_check(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) { - static char *texts[] = { "No Lock", "Lock" }; + static const char *const texts[] = { "No Lock", "Lock" }; ENUMERATED_CTL_INFO(uinfo, texts); return 0; } @@ -3733,18 +3976,23 @@ if (hdspm->tco) { switch (hdspm->io_type) { case MADI: + status = hdspm_read(hdspm, HDSPM_statusRegister); + if (status & HDSPM_tcoLockMadi) { + if (status & HDSPM_tcoSync) + return 2; + else + return 1; + } + return 0; case AES32: status = hdspm_read(hdspm, HDSPM_statusRegister); - if (status & HDSPM_tcoLock) { + if (status & HDSPM_tcoLockAes) { if (status & HDSPM_tcoSync) return 2; else return 1; } return 0; - - break; - case RayDAT: case AIO: status = hdspm_read(hdspm, HDSPM_RD_STATUS_1); @@ -3754,7 +4002,6 @@ if (status & 0x4000000) return 1; /* Lock */ return 0; /* No signal */ - break; default: break; @@ -3795,7 +4042,8 @@ case 5: /* SYNC IN */ val = hdspm_sync_in_sync_check(hdspm); break; default: - val = hdspm_s1_sync_check(hdspm, ucontrol->id.index-1); + val = hdspm_s1_sync_check(hdspm, + kcontrol->private_value-1); } break; @@ -3857,9 +4105,9 @@ -/** +/* * TCO controls - **/ + */ static void hdspm_tco_write(struct hdspm *hdspm) { unsigned int tc[4] = { 0, 0, 0, 0}; @@ -3963,7 +4211,8 @@ static int snd_hdspm_info_tco_sample_rate(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) { - static char *texts[] = { "44.1 kHz", "48 kHz" }; + /* TODO freq from app could be supported here, see tco->samplerate */ + static const char *const texts[] = { "44.1 kHz", "48 kHz" }; ENUMERATED_CTL_INFO(uinfo, texts); return 0; } @@ -4009,7 +4258,8 @@ static int snd_hdspm_info_tco_pull(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) { - static char *texts[] = { "0", "+ 0.1 %", "- 0.1 %", "+ 4 %", "- 4 %" }; + static const char *const texts[] = { "0", "+ 0.1 %", "- 0.1 %", + "+ 4 %", "- 4 %" }; ENUMERATED_CTL_INFO(uinfo, texts); return 0; } @@ -4054,7 +4304,7 @@ static int snd_hdspm_info_tco_wck_conversion(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) { - static char *texts[] = { "1:1", "44.1 -> 48", "48 -> 44.1" }; + static const char *const texts[] = { "1:1", "44.1 -> 48", "48 -> 44.1" }; ENUMERATED_CTL_INFO(uinfo, texts); return 0; } @@ -4100,7 +4350,7 @@ static int snd_hdspm_info_tco_frame_rate(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) { - static char *texts[] = { "24 fps", "25 fps", "29.97fps", + static const char *const texts[] = { "24 fps", "25 fps", "29.97fps", "29.97 dfps", "30 fps", "30 dfps" }; ENUMERATED_CTL_INFO(uinfo, texts); return 0; @@ -4147,7 +4397,7 @@ static int snd_hdspm_info_tco_sync_source(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) { - static char *texts[] = { "LTC", "Video", "WCK" }; + static const char *const texts[] = { "LTC", "Video", "WCK" }; ENUMERATED_CTL_INFO(uinfo, texts); return 0; } @@ -4272,7 +4522,6 @@ HDSPM_INTERNAL_CLOCK("Internal Clock", 0), HDSPM_SYSTEM_CLOCK_MODE("System Clock Mode", 0), HDSPM_PREF_SYNC_REF("Preferred Sync Reference", 0), - HDSPM_AUTOSYNC_REF("AutoSync Reference", 0), HDSPM_SYSTEM_SAMPLE_RATE("System Sample Rate", 0), HDSPM_AUTOSYNC_SAMPLE_RATE("External Rate", 0), HDSPM_SYNC_CHECK("WC SyncCheck", 0), @@ -4286,7 +4535,16 @@ HDSPM_AUTOSYNC_SAMPLE_RATE("SPDIF Frequency", 2), HDSPM_AUTOSYNC_SAMPLE_RATE("ADAT Frequency", 3), HDSPM_AUTOSYNC_SAMPLE_RATE("TCO Frequency", 4), - HDSPM_AUTOSYNC_SAMPLE_RATE("SYNC IN Frequency", 5) + HDSPM_AUTOSYNC_SAMPLE_RATE("SYNC IN Frequency", 5), + HDSPM_CONTROL_TRISTATE("S/PDIF Input", HDSPM_c0_Input0), + HDSPM_TOGGLE_SETTING("S/PDIF Out Optical", HDSPM_c0_Spdif_Opt), + HDSPM_TOGGLE_SETTING("S/PDIF Out Professional", HDSPM_c0_Pro), + HDSPM_TOGGLE_SETTING("ADAT internal (AEB/TEB)", HDSPM_c0_AEB1), + HDSPM_TOGGLE_SETTING("XLR Breakout Cable", HDSPM_c0_Sym6db), + HDSPM_TOGGLE_SETTING("Single Speed WordClock Out", HDSPM_c0_Wck48), + HDSPM_CONTROL_TRISTATE("Input Level", HDSPM_c0_AD_GAIN0), + HDSPM_CONTROL_TRISTATE("Output Level", HDSPM_c0_DA_GAIN0), + HDSPM_CONTROL_TRISTATE("Phones Level", HDSPM_c0_PH_GAIN0) /* HDSPM_INPUT_SELECT("Input Select", 0), @@ -4323,7 +4581,9 @@ HDSPM_AUTOSYNC_SAMPLE_RATE("ADAT3 Frequency", 5), HDSPM_AUTOSYNC_SAMPLE_RATE("ADAT4 Frequency", 6), HDSPM_AUTOSYNC_SAMPLE_RATE("TCO Frequency", 7), - HDSPM_AUTOSYNC_SAMPLE_RATE("SYNC IN Frequency", 8) + HDSPM_AUTOSYNC_SAMPLE_RATE("SYNC IN Frequency", 8), + HDSPM_TOGGLE_SETTING("S/PDIF Out Professional", HDSPM_c0_Pro), + HDSPM_TOGGLE_SETTING("Single Speed WordClock Out", HDSPM_c0_Wck48) }; static struct snd_kcontrol_new snd_hdspm_controls_aes32[] = { @@ -4333,7 +4593,7 @@ HDSPM_PREF_SYNC_REF("Preferred Sync Reference", 0), HDSPM_AUTOSYNC_REF("AutoSync Reference", 0), HDSPM_SYSTEM_SAMPLE_RATE("System Sample Rate", 0), - HDSPM_AUTOSYNC_SAMPLE_RATE("External Rate", 0), + HDSPM_AUTOSYNC_SAMPLE_RATE("External Rate", 11), HDSPM_SYNC_CHECK("WC Sync Check", 0), HDSPM_SYNC_CHECK("AES1 Sync Check", 1), HDSPM_SYNC_CHECK("AES2 Sync Check", 2), @@ -4489,77 +4749,22 @@ ------------------------------------------------------------*/ static void -snd_hdspm_proc_read_madi(struct snd_info_entry * entry, - struct snd_info_buffer *buffer) +snd_hdspm_proc_read_tco(struct snd_info_entry *entry, + struct snd_info_buffer *buffer) { struct hdspm *hdspm = entry->private_data; - unsigned int status, status2, control, freq; - - char *pref_sync_ref; - char *autosync_ref; - char *system_clock_mode; - char *insel; - int x, x2; - - /* TCO stuff */ + unsigned int status, control; int a, ltc, frames, seconds, minutes, hours; unsigned int period; u64 freq_const = 0; u32 rate; + snd_iprintf(buffer, "--- TCO ---\n"); + status = hdspm_read(hdspm, HDSPM_statusRegister); - status2 = hdspm_read(hdspm, HDSPM_statusRegister2); control = hdspm->control_register; - freq = hdspm_read(hdspm, HDSPM_timecodeRegister); - snd_iprintf(buffer, "%s (Card #%d) Rev.%x Status2first3bits: %x\n", - hdspm->card_name, hdspm->card->number + 1, - hdspm->firmware_rev, - (status2 & HDSPM_version0) | - (status2 & HDSPM_version1) | (status2 & - HDSPM_version2)); - snd_iprintf(buffer, "HW Serial: 0x%06x%06x\n", - (hdspm_read(hdspm, HDSPM_midiStatusIn1)>>8) & 0xFFFFFF, - hdspm->serial); - - snd_iprintf(buffer, "IRQ: %d Registers bus: 0x%lx VM: 0x%lx\n", - hdspm->irq, hdspm->port, (unsigned long)hdspm->iobase); - - snd_iprintf(buffer, "--- System ---\n"); - - snd_iprintf(buffer, - "IRQ Pending: Audio=%d, MIDI0=%d, MIDI1=%d, IRQcount=%d\n", - status & HDSPM_audioIRQPending, - (status & HDSPM_midi0IRQPending) ? 1 : 0, - (status & HDSPM_midi1IRQPending) ? 1 : 0, - hdspm->irq_count); - snd_iprintf(buffer, - "HW pointer: id = %d, rawptr = %d (%d->%d) " - "estimated= %ld (bytes)\n", - ((status & HDSPM_BufferID) ? 1 : 0), - (status & HDSPM_BufferPositionMask), - (status & HDSPM_BufferPositionMask) % - (2 * (int)hdspm->period_bytes), - ((status & HDSPM_BufferPositionMask) - 64) % - (2 * (int)hdspm->period_bytes), - (long) hdspm_hw_pointer(hdspm) * 4); - - snd_iprintf(buffer, - "MIDI FIFO: Out1=0x%x, Out2=0x%x, In1=0x%x, In2=0x%x \n", - hdspm_read(hdspm, HDSPM_midiStatusOut0) & 0xFF, - hdspm_read(hdspm, HDSPM_midiStatusOut1) & 0xFF, - hdspm_read(hdspm, HDSPM_midiStatusIn0) & 0xFF, - hdspm_read(hdspm, HDSPM_midiStatusIn1) & 0xFF); - snd_iprintf(buffer, - "MIDIoverMADI FIFO: In=0x%x, Out=0x%x \n", - hdspm_read(hdspm, HDSPM_midiStatusIn2) & 0xFF, - hdspm_read(hdspm, HDSPM_midiStatusOut2) & 0xFF); - snd_iprintf(buffer, - "Register: ctrl1=0x%x, ctrl2=0x%x, status1=0x%x, " - "status2=0x%x\n", - hdspm->control_register, hdspm->control2_register, - status, status2); if (status & HDSPM_tco_detect) { snd_iprintf(buffer, "TCO module detected.\n"); a = hdspm_read(hdspm, HDSPM_RD_TCO+4); @@ -4653,6 +4858,72 @@ } else { snd_iprintf(buffer, "No TCO module detected.\n"); } +} + +static void +snd_hdspm_proc_read_madi(struct snd_info_entry *entry, + struct snd_info_buffer *buffer) +{ + struct hdspm *hdspm = entry->private_data; + unsigned int status, status2; + + char *pref_sync_ref; + char *autosync_ref; + char *system_clock_mode; + int x, x2; + + status = hdspm_read(hdspm, HDSPM_statusRegister); + status2 = hdspm_read(hdspm, HDSPM_statusRegister2); + + snd_iprintf(buffer, "%s (Card #%d) Rev.%x Status2first3bits: %x\n", + hdspm->card_name, hdspm->card->number + 1, + hdspm->firmware_rev, + (status2 & HDSPM_version0) | + (status2 & HDSPM_version1) | (status2 & + HDSPM_version2)); + + snd_iprintf(buffer, "HW Serial: 0x%06x%06x\n", + (hdspm_read(hdspm, HDSPM_midiStatusIn1)>>8) & 0xFFFFFF, + hdspm->serial); + + snd_iprintf(buffer, "IRQ: %d Registers bus: 0x%lx VM: 0x%lx\n", + hdspm->irq, hdspm->port, (unsigned long)hdspm->iobase); + + snd_iprintf(buffer, "--- System ---\n"); + + snd_iprintf(buffer, + "IRQ Pending: Audio=%d, MIDI0=%d, MIDI1=%d, IRQcount=%d\n", + status & HDSPM_audioIRQPending, + (status & HDSPM_midi0IRQPending) ? 1 : 0, + (status & HDSPM_midi1IRQPending) ? 1 : 0, + hdspm->irq_count); + snd_iprintf(buffer, + "HW pointer: id = %d, rawptr = %d (%d->%d) " + "estimated= %ld (bytes)\n", + ((status & HDSPM_BufferID) ? 1 : 0), + (status & HDSPM_BufferPositionMask), + (status & HDSPM_BufferPositionMask) % + (2 * (int)hdspm->period_bytes), + ((status & HDSPM_BufferPositionMask) - 64) % + (2 * (int)hdspm->period_bytes), + (long) hdspm_hw_pointer(hdspm) * 4); + + snd_iprintf(buffer, + "MIDI FIFO: Out1=0x%x, Out2=0x%x, In1=0x%x, In2=0x%x \n", + hdspm_read(hdspm, HDSPM_midiStatusOut0) & 0xFF, + hdspm_read(hdspm, HDSPM_midiStatusOut1) & 0xFF, + hdspm_read(hdspm, HDSPM_midiStatusIn0) & 0xFF, + hdspm_read(hdspm, HDSPM_midiStatusIn1) & 0xFF); + snd_iprintf(buffer, + "MIDIoverMADI FIFO: In=0x%x, Out=0x%x \n", + hdspm_read(hdspm, HDSPM_midiStatusIn2) & 0xFF, + hdspm_read(hdspm, HDSPM_midiStatusOut2) & 0xFF); + snd_iprintf(buffer, + "Register: ctrl1=0x%x, ctrl2=0x%x, status1=0x%x, " + "status2=0x%x\n", + hdspm->control_register, hdspm->control2_register, + status, status2); + snd_iprintf(buffer, "--- Settings ---\n"); @@ -4665,17 +4936,6 @@ snd_iprintf(buffer, "Line out: %s\n", (hdspm->control_register & HDSPM_LineOut) ? "on " : "off"); - switch (hdspm->control_register & HDSPM_InputMask) { - case HDSPM_InputOptical: - insel = "Optical"; - break; - case HDSPM_InputCoaxial: - insel = "Coaxial"; - break; - default: - insel = "Unknown"; - } - snd_iprintf(buffer, "ClearTrackMarker = %s, Transmit in %s Channel Mode, " "Auto Input %s\n", @@ -4756,6 +5016,9 @@ (status & HDSPM_RX_64ch) ? "64 channels" : "56 channels"); + /* call readout function for TCO specific status */ + snd_hdspm_proc_read_tco(entry, buffer); + snd_iprintf(buffer, "\n"); } @@ -4897,11 +5160,18 @@ autosync_ref = "AES7"; break; case HDSPM_AES32_AUTOSYNC_FROM_AES8: autosync_ref = "AES8"; break; + case HDSPM_AES32_AUTOSYNC_FROM_TCO: + autosync_ref = "TCO"; break; + case HDSPM_AES32_AUTOSYNC_FROM_SYNC_IN: + autosync_ref = "Sync In"; break; default: autosync_ref = "---"; break; } snd_iprintf(buffer, "AutoSync ref = %s\n", autosync_ref); + /* call readout function for TCO specific status */ + snd_hdspm_proc_read_tco(entry, buffer); + snd_iprintf(buffer, "\n"); } @@ -4910,15 +5180,13 @@ struct snd_info_buffer *buffer) { struct hdspm *hdspm = entry->private_data; - unsigned int status1, status2, status3, control, i; + unsigned int status1, status2, status3, i; unsigned int lock, sync; status1 = hdspm_read(hdspm, HDSPM_RD_STATUS_1); /* s1 */ status2 = hdspm_read(hdspm, HDSPM_RD_STATUS_2); /* freq */ status3 = hdspm_read(hdspm, HDSPM_RD_STATUS_3); /* s2 */ - control = hdspm->control_register; - snd_iprintf(buffer, "STATUS1: 0x%08x\n", status1); snd_iprintf(buffer, "STATUS2: 0x%08x\n", status2); snd_iprintf(buffer, "STATUS3: 0x%08x\n", status3); @@ -5085,7 +5353,7 @@ case AES32: hdspm->control_register = - HDSPM_ClockModeMaster | /* Master Cloack Mode on */ + HDSPM_ClockModeMaster | /* Master Clock Mode on */ hdspm_encode_latency(7) | /* latency max=8192samples */ HDSPM_SyncRef0 | /* AES1 is syncclock */ HDSPM_LineOut | /* Analog output in */ @@ -5111,9 +5379,8 @@ all_in_all_mixer(hdspm, 0 * UNITY_GAIN); - if (hdspm->io_type == AIO || hdspm->io_type == RayDAT) { + if (hdspm_is_raydat_or_aio(hdspm)) hdspm_write(hdspm, HDSPM_WR_SETTINGS, hdspm->settings_register); - } /* set a default rate so that the channel map is set up. */ hdspm_set_rate(hdspm, 48000, 1); @@ -5140,7 +5407,7 @@ HDSPM_midi2IRQPending | HDSPM_midi3IRQPending); /* now = get_cycles(); */ - /** + /* * LAT_2..LAT_0 period counter (win) counter (mac) * 6 4096 ~256053425 ~514672358 * 5 2048 ~128024983 ~257373821 @@ -5149,9 +5416,9 @@ * 2 256 ~16003039 ~32260176 * 1 128 ~7998738 ~16194507 * 0 64 ~3998231 ~8191558 - **/ + */ /* - snd_printk(KERN_INFO "snd_hdspm_interrupt %llu @ %llx\n", + dev_info(hdspm->card->dev, "snd_hdspm_interrupt %llu @ %llx\n", now-hdspm->last_interrupt, status & 0xFFC0); hdspm->last_interrupt = now; */ @@ -5288,7 +5555,7 @@ spin_lock_irq(&hdspm->lock); err = hdspm_set_rate(hdspm, params_rate(params), 0); if (err < 0) { - snd_printk(KERN_INFO "err on hdspm_set_rate: %d\n", err); + dev_info(hdspm->card->dev, "err on hdspm_set_rate: %d\n", err); spin_unlock_irq(&hdspm->lock); _snd_pcm_hw_param_setempty(params, SNDRV_PCM_HW_PARAM_RATE); @@ -5299,7 +5566,8 @@ err = hdspm_set_interrupt_interval(hdspm, params_period_size(params)); if (err < 0) { - snd_printk(KERN_INFO "err on hdspm_set_interrupt_interval: %d\n", err); + dev_info(hdspm->card->dev, + "err on hdspm_set_interrupt_interval: %d\n", err); _snd_pcm_hw_param_setempty(params, SNDRV_PCM_HW_PARAM_PERIOD_SIZE); return err; @@ -5315,7 +5583,8 @@ err = snd_pcm_lib_malloc_pages(substream, HDSPM_DMA_AREA_BYTES); if (err < 0) { - snd_printk(KERN_INFO "err on snd_pcm_lib_malloc_pages: %d\n", err); + dev_info(hdspm->card->dev, + "err on snd_pcm_lib_malloc_pages: %d\n", err); return err; } @@ -5329,7 +5598,8 @@ hdspm->playback_buffer = (unsigned char *) substream->runtime->dma_area; - snd_printdd("Allocated sample buffer for playback at %p\n", + dev_dbg(hdspm->card->dev, + "Allocated sample buffer for playback at %p\n", hdspm->playback_buffer); } else { hdspm_set_sgbuf(hdspm, substream, HDSPM_pageAddressBufferIn, @@ -5340,18 +5610,21 @@ hdspm->capture_buffer = (unsigned char *) substream->runtime->dma_area; - snd_printdd("Allocated sample buffer for capture at %p\n", + dev_dbg(hdspm->card->dev, + "Allocated sample buffer for capture at %p\n", hdspm->capture_buffer); } /* - snd_printdd("Allocated sample buffer for %s at 0x%08X\n", + dev_dbg(hdspm->card->dev, + "Allocated sample buffer for %s at 0x%08X\n", substream->stream == SNDRV_PCM_STREAM_PLAYBACK ? "playback" : "capture", snd_pcm_sgbuf_get_addr(substream, 0)); */ /* - snd_printdd("set_hwparams: %s %d Hz, %d channels, bs = %d\n", + dev_dbg(hdspm->card->dev, + "set_hwparams: %s %d Hz, %d channels, bs = %d\n", substream->stream == SNDRV_PCM_STREAM_PLAYBACK ? "playback" : "capture", params_rate(params), params_channels(params), @@ -5359,15 +5632,27 @@ */ + /* For AES cards, the float format bit is the same as the + * preferred sync reference. Since we don't want to break + * sync settings, we have to skip the remaining part of this + * function. + */ + if (hdspm->io_type == AES32) { + return 0; + } + + /* Switch to native float format if requested */ if (SNDRV_PCM_FORMAT_FLOAT_LE == params_format(params)) { if (!(hdspm->control_register & HDSPe_FLOAT_FORMAT)) - snd_printk(KERN_INFO "hdspm: Switching to native 32bit LE float format.\n"); + dev_info(hdspm->card->dev, + "Switching to native 32bit LE float format.\n"); hdspm->control_register |= HDSPe_FLOAT_FORMAT; } else if (SNDRV_PCM_FORMAT_S32_LE == params_format(params)) { if (hdspm->control_register & HDSPe_FLOAT_FORMAT) - snd_printk(KERN_INFO "hdspm: Switching to native 32bit LE integer format.\n"); + dev_info(hdspm->card->dev, + "Switching to native 32bit LE integer format.\n"); hdspm->control_register &= ~HDSPe_FLOAT_FORMAT; } @@ -5410,12 +5695,16 @@ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { if (snd_BUG_ON(info->channel >= hdspm->max_channels_out)) { - snd_printk(KERN_INFO "snd_hdspm_channel_info: output channel out of range (%d)\n", info->channel); + dev_info(hdspm->card->dev, + "snd_hdspm_channel_info: output channel out of range (%d)\n", + info->channel); return -EINVAL; } if (hdspm->channel_map_out[info->channel] < 0) { - snd_printk(KERN_INFO "snd_hdspm_channel_info: output channel %d mapped out\n", info->channel); + dev_info(hdspm->card->dev, + "snd_hdspm_channel_info: output channel %d mapped out\n", + info->channel); return -EINVAL; } @@ -5423,12 +5712,16 @@ HDSPM_CHANNEL_BUFFER_BYTES; } else { if (snd_BUG_ON(info->channel >= hdspm->max_channels_in)) { - snd_printk(KERN_INFO "snd_hdspm_channel_info: input channel out of range (%d)\n", info->channel); + dev_info(hdspm->card->dev, + "snd_hdspm_channel_info: input channel out of range (%d)\n", + info->channel); return -EINVAL; } if (hdspm->channel_map_in[info->channel] < 0) { - snd_printk(KERN_INFO "snd_hdspm_channel_info: input channel %d mapped out\n", info->channel); + dev_info(hdspm->card->dev, + "snd_hdspm_channel_info: input channel %d mapped out\n", + info->channel); return -EINVAL; } @@ -5758,23 +6051,30 @@ .mask = 0 }; -static int snd_hdspm_playback_open(struct snd_pcm_substream *substream) +static int snd_hdspm_open(struct snd_pcm_substream *substream) { struct hdspm *hdspm = snd_pcm_substream_chip(substream); struct snd_pcm_runtime *runtime = substream->runtime; + bool playback = (substream->stream == SNDRV_PCM_STREAM_PLAYBACK); spin_lock_irq(&hdspm->lock); - snd_pcm_set_sync(substream); + runtime->hw = (playback) ? snd_hdspm_playback_subinfo : + snd_hdspm_capture_subinfo; + if (playback) { + if (hdspm->capture_substream == NULL) + hdspm_stop_audio(hdspm); - runtime->hw = snd_hdspm_playback_subinfo; - - if (hdspm->capture_substream == NULL) - hdspm_stop_audio(hdspm); + hdspm->playback_pid = current->pid; + hdspm->playback_substream = substream; + } else { + if (hdspm->playback_substream == NULL) + hdspm_stop_audio(hdspm); - hdspm->playback_pid = current->pid; - hdspm->playback_substream = substream; + hdspm->capture_pid = current->pid; + hdspm->capture_substream = substream; + } spin_unlock_irq(&hdspm->lock); @@ -5788,18 +6088,17 @@ SNDRV_PCM_HW_PARAM_PERIOD_SIZE, 32, 4096); /* RayDAT & AIO have a fixed buffer of 16384 samples per channel */ - snd_pcm_hw_constraint_minmax(runtime, + snd_pcm_hw_constraint_single(runtime, SNDRV_PCM_HW_PARAM_BUFFER_SIZE, - 16384, 16384); + 16384); break; default: snd_pcm_hw_constraint_minmax(runtime, SNDRV_PCM_HW_PARAM_PERIOD_SIZE, 64, 8192); - snd_pcm_hw_constraint_minmax(runtime, - SNDRV_PCM_HW_PARAM_PERIODS, - 2, 2); + snd_pcm_hw_constraint_single(runtime, + SNDRV_PCM_HW_PARAM_PERIODS, 2); break; } @@ -5809,108 +6108,42 @@ &hdspm_hw_constraints_aes32_sample_rates); } else { snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_RATE, - snd_hdspm_hw_rule_rate_out_channels, hdspm, + (playback ? + snd_hdspm_hw_rule_rate_out_channels : + snd_hdspm_hw_rule_rate_in_channels), hdspm, SNDRV_PCM_HW_PARAM_CHANNELS, -1); } snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_CHANNELS, - snd_hdspm_hw_rule_out_channels, hdspm, + (playback ? snd_hdspm_hw_rule_out_channels : + snd_hdspm_hw_rule_in_channels), hdspm, SNDRV_PCM_HW_PARAM_CHANNELS, -1); snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_CHANNELS, - snd_hdspm_hw_rule_out_channels_rate, hdspm, + (playback ? snd_hdspm_hw_rule_out_channels_rate : + snd_hdspm_hw_rule_in_channels_rate), hdspm, SNDRV_PCM_HW_PARAM_RATE, -1); return 0; } -static int snd_hdspm_playback_release(struct snd_pcm_substream *substream) +static int snd_hdspm_release(struct snd_pcm_substream *substream) { struct hdspm *hdspm = snd_pcm_substream_chip(substream); + bool playback = (substream->stream == SNDRV_PCM_STREAM_PLAYBACK); spin_lock_irq(&hdspm->lock); - hdspm->playback_pid = -1; - hdspm->playback_substream = NULL; - - spin_unlock_irq(&hdspm->lock); - - return 0; -} - - -static int snd_hdspm_capture_open(struct snd_pcm_substream *substream) -{ - struct hdspm *hdspm = snd_pcm_substream_chip(substream); - struct snd_pcm_runtime *runtime = substream->runtime; - - spin_lock_irq(&hdspm->lock); - snd_pcm_set_sync(substream); - runtime->hw = snd_hdspm_capture_subinfo; - - if (hdspm->playback_substream == NULL) - hdspm_stop_audio(hdspm); - - hdspm->capture_pid = current->pid; - hdspm->capture_substream = substream; - - spin_unlock_irq(&hdspm->lock); - - snd_pcm_hw_constraint_msbits(runtime, 0, 32, 24); - snd_pcm_hw_constraint_pow2(runtime, 0, SNDRV_PCM_HW_PARAM_PERIOD_SIZE); - - switch (hdspm->io_type) { - case AIO: - case RayDAT: - snd_pcm_hw_constraint_minmax(runtime, - SNDRV_PCM_HW_PARAM_PERIOD_SIZE, - 32, 4096); - snd_pcm_hw_constraint_minmax(runtime, - SNDRV_PCM_HW_PARAM_BUFFER_SIZE, - 16384, 16384); - break; - - default: - snd_pcm_hw_constraint_minmax(runtime, - SNDRV_PCM_HW_PARAM_PERIOD_SIZE, - 64, 8192); - snd_pcm_hw_constraint_minmax(runtime, - SNDRV_PCM_HW_PARAM_PERIODS, - 2, 2); - break; - } - - if (AES32 == hdspm->io_type) { - runtime->hw.rates |= SNDRV_PCM_RATE_KNOT; - snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_RATE, - &hdspm_hw_constraints_aes32_sample_rates); + if (playback) { + hdspm->playback_pid = -1; + hdspm->playback_substream = NULL; } else { - snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_RATE, - snd_hdspm_hw_rule_rate_in_channels, hdspm, - SNDRV_PCM_HW_PARAM_CHANNELS, -1); + hdspm->capture_pid = -1; + hdspm->capture_substream = NULL; } - snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_CHANNELS, - snd_hdspm_hw_rule_in_channels, hdspm, - SNDRV_PCM_HW_PARAM_CHANNELS, -1); - - snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_CHANNELS, - snd_hdspm_hw_rule_in_channels_rate, hdspm, - SNDRV_PCM_HW_PARAM_RATE, -1); - - return 0; -} - -static int snd_hdspm_capture_release(struct snd_pcm_substream *substream) -{ - struct hdspm *hdspm = snd_pcm_substream_chip(substream); - - spin_lock_irq(&hdspm->lock); - - hdspm->capture_pid = -1; - hdspm->capture_substream = NULL; - spin_unlock_irq(&hdspm->lock); + return 0; } @@ -5984,7 +6217,7 @@ s = copy_to_user(argp, levels, sizeof(struct hdspm_peak_rms)); if (0 != s) { - /* snd_printk(KERN_ERR "copy_to_user(.., .., %lu): %lu + /* dev_err(hdspm->card->dev, "copy_to_user(.., .., %lu): %lu [Levels]\n", sizeof(struct hdspm_peak_rms), s); */ return -EFAULT; @@ -6007,7 +6240,7 @@ ltc.format = fps_2997; break; default: - ltc.format = 30; + ltc.format = fps_30; break; } if (i & HDSPM_TCO1_set_drop_frame_flag) { @@ -6030,7 +6263,7 @@ s = copy_to_user(argp, <c, sizeof(struct hdspm_ltc)); if (0 != s) { /* - snd_printk(KERN_ERR "copy_to_user(.., .., %lu): %lu [LTC]\n", sizeof(struct hdspm_ltc), s); */ + dev_err(hdspm->card->dev, "copy_to_user(.., .., %lu): %lu [LTC]\n", sizeof(struct hdspm_ltc), s); */ return -EFAULT; } @@ -6101,7 +6334,7 @@ memset(&hdspm_version, 0, sizeof(hdspm_version)); hdspm_version.card_type = hdspm->io_type; - strncpy(hdspm_version.cardname, hdspm->card_name, + strlcpy(hdspm_version.cardname, hdspm->card_name, sizeof(hdspm_version.cardname)); hdspm_version.serial = hdspm->serial; hdspm_version.firmware_rev = hdspm->firmware_rev; @@ -6128,21 +6361,9 @@ return 0; } -static struct snd_pcm_ops snd_hdspm_playback_ops = { - .open = snd_hdspm_playback_open, - .close = snd_hdspm_playback_release, - .ioctl = snd_hdspm_ioctl, - .hw_params = snd_hdspm_hw_params, - .hw_free = snd_hdspm_hw_free, - .prepare = snd_hdspm_prepare, - .trigger = snd_hdspm_trigger, - .pointer = snd_hdspm_hw_pointer, - .page = snd_pcm_sgbuf_ops_page, -}; - -static struct snd_pcm_ops snd_hdspm_capture_ops = { - .open = snd_hdspm_capture_open, - .close = snd_hdspm_capture_release, +static struct snd_pcm_ops snd_hdspm_ops = { + .open = snd_hdspm_open, + .close = snd_hdspm_release, .ioctl = snd_hdspm_ioctl, .hw_params = snd_hdspm_hw_params, .hw_free = snd_hdspm_hw_free, @@ -6195,11 +6416,13 @@ wanted, wanted); if (err < 0) { - snd_printdd("Could not preallocate %zd Bytes\n", wanted); + dev_dbg(hdspm->card->dev, + "Could not preallocate %zd Bytes\n", wanted); return err; } else - snd_printdd(" Preallocated %zd Bytes\n", wanted); + dev_dbg(hdspm->card->dev, + " Preallocated %zd Bytes\n", wanted); return 0; } @@ -6234,9 +6457,9 @@ strcpy(pcm->name, hdspm->card_name); snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, - &snd_hdspm_playback_ops); + &snd_hdspm_ops); snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, - &snd_hdspm_capture_ops); + &snd_hdspm_ops); pcm->info_flags = SNDRV_PCM_INFO_JOINT_DUPLEX; @@ -6260,7 +6483,7 @@ { int err, i; - snd_printdd("Create card...\n"); + dev_dbg(card->dev, "Create card...\n"); err = snd_hdspm_create_pcm(card, hdspm); if (err < 0) return err; @@ -6282,7 +6505,7 @@ if (err < 0) return err; - snd_printdd("proc init...\n"); + dev_dbg(card->dev, "proc init...\n"); snd_hdspm_proc_init(hdspm); hdspm->system_sample_rate = -1; @@ -6293,23 +6516,23 @@ hdspm->capture_substream = NULL; hdspm->playback_substream = NULL; - snd_printdd("Set defaults...\n"); + dev_dbg(card->dev, "Set defaults...\n"); err = snd_hdspm_set_defaults(hdspm); if (err < 0) return err; - snd_printdd("Update mixer controls...\n"); + dev_dbg(card->dev, "Update mixer controls...\n"); hdspm_update_simple_mixer_controls(hdspm); - snd_printdd("Initializeing complete ???\n"); + dev_dbg(card->dev, "Initializeing complete ???\n"); err = snd_card_register(card); if (err < 0) { - snd_printk(KERN_ERR "HDSPM: error registering card\n"); + dev_err(card->dev, "error registering card\n"); return err; } - snd_printdd("... yes now\n"); + dev_dbg(card->dev, "... yes now\n"); return 0; } @@ -6363,8 +6586,8 @@ hdspm->card_name = "RME MADI"; hdspm->midiPorts = 3; } else { - snd_printk(KERN_ERR - "HDSPM: unknown firmware revision %x\n", + dev_err(card->dev, + "unknown firmware revision %x\n", hdspm->firmware_rev); return -ENODEV; } @@ -6383,36 +6606,35 @@ hdspm->port = pci_resource_start(pci, 0); io_extent = pci_resource_len(pci, 0); - snd_printdd("grabbed memory region 0x%lx-0x%lx\n", + dev_dbg(card->dev, "grabbed memory region 0x%lx-0x%lx\n", hdspm->port, hdspm->port + io_extent - 1); hdspm->iobase = ioremap_nocache(hdspm->port, io_extent); if (!hdspm->iobase) { - snd_printk(KERN_ERR "HDSPM: " - "unable to remap region 0x%lx-0x%lx\n", + dev_err(card->dev, "unable to remap region 0x%lx-0x%lx\n", hdspm->port, hdspm->port + io_extent - 1); return -EBUSY; } - snd_printdd("remapped region (0x%lx) 0x%lx-0x%lx\n", + dev_dbg(card->dev, "remapped region (0x%lx) 0x%lx-0x%lx\n", (unsigned long)hdspm->iobase, hdspm->port, hdspm->port + io_extent - 1); if (request_irq(pci->irq, snd_hdspm_interrupt, IRQF_SHARED, KBUILD_MODNAME, hdspm)) { - snd_printk(KERN_ERR "HDSPM: unable to use IRQ %d\n", pci->irq); + dev_err(card->dev, "unable to use IRQ %d\n", pci->irq); return -EBUSY; } - snd_printdd("use IRQ %d\n", pci->irq); + dev_dbg(card->dev, "use IRQ %d\n", pci->irq); hdspm->irq = pci->irq; - snd_printdd("kmalloc Mixer memory of %zd Bytes\n", + dev_dbg(card->dev, "kmalloc Mixer memory of %zd Bytes\n", sizeof(struct hdspm_mixer)); hdspm->mixer = kzalloc(sizeof(struct hdspm_mixer), GFP_KERNEL); if (!hdspm->mixer) { - snd_printk(KERN_ERR "HDSPM: " - "unable to kmalloc Mixer memory of %d Bytes\n", + dev_err(card->dev, + "unable to kmalloc Mixer memory of %d Bytes\n", (int)sizeof(struct hdspm_mixer)); return -ENOMEM; } @@ -6473,10 +6695,6 @@ break; case AIO: - if (0 == (hdspm_read(hdspm, HDSPM_statusRegister2) & HDSPM_s2_AEBI_D)) { - snd_printk(KERN_INFO "HDSPM: AEB input board found, but not supported\n"); - } - hdspm->ss_in_channels = AIO_IN_SS_CHANNELS; hdspm->ds_in_channels = AIO_IN_DS_CHANNELS; hdspm->qs_in_channels = AIO_IN_QS_CHANNELS; @@ -6484,6 +6702,20 @@ hdspm->ds_out_channels = AIO_OUT_DS_CHANNELS; hdspm->qs_out_channels = AIO_OUT_QS_CHANNELS; + if (0 == (hdspm_read(hdspm, HDSPM_statusRegister2) & HDSPM_s2_AEBI_D)) { + dev_info(card->dev, "AEB input board found\n"); + hdspm->ss_in_channels += 4; + hdspm->ds_in_channels += 4; + hdspm->qs_in_channels += 4; + } + + if (0 == (hdspm_read(hdspm, HDSPM_statusRegister2) & HDSPM_s2_AEBO_D)) { + dev_info(card->dev, "AEB output board found\n"); + hdspm->ss_out_channels += 4; + hdspm->ds_out_channels += 4; + hdspm->qs_out_channels += 4; + } + hdspm->channel_map_out_ss = channel_map_aio_out_ss; hdspm->channel_map_out_ds = channel_map_aio_out_ds; hdspm->channel_map_out_qs = channel_map_aio_out_qs; @@ -6545,13 +6777,14 @@ if (NULL != hdspm->tco) { hdspm_tco_write(hdspm); } - snd_printk(KERN_INFO "HDSPM: AIO/RayDAT TCO module found\n"); + dev_info(card->dev, "AIO/RayDAT TCO module found\n"); } else { hdspm->tco = NULL; } break; case MADI: + case AES32: if (hdspm_read(hdspm, HDSPM_statusRegister) & HDSPM_tco_detect) { hdspm->midiPorts++; hdspm->tco = kzalloc(sizeof(struct hdspm_tco), @@ -6559,7 +6792,7 @@ if (NULL != hdspm->tco) { hdspm_tco_write(hdspm); } - snd_printk(KERN_INFO "HDSPM: MADI TCO module found\n"); + dev_info(card->dev, "MADI/AES TCO module found\n"); } else { hdspm->tco = NULL; } @@ -6574,10 +6807,12 @@ case AES32: if (hdspm->tco) { hdspm->texts_autosync = texts_autosync_aes_tco; - hdspm->texts_autosync_items = 10; + hdspm->texts_autosync_items = + ARRAY_SIZE(texts_autosync_aes_tco); } else { hdspm->texts_autosync = texts_autosync_aes; - hdspm->texts_autosync_items = 9; + hdspm->texts_autosync_items = + ARRAY_SIZE(texts_autosync_aes); } break; @@ -6639,7 +6874,7 @@ } } - snd_printdd("create alsa devices.\n"); + dev_dbg(card->dev, "create alsa devices.\n"); err = snd_hdspm_create_alsa_devices(card, hdspm); if (err < 0) return err; @@ -6668,9 +6903,7 @@ free_irq(hdspm->irq, (void *) hdspm); kfree(hdspm->mixer); - - if (hdspm->iobase) - iounmap(hdspm->iobase); + iounmap(hdspm->iobase); if (hdspm->port) pci_release_regions(hdspm->pci); @@ -6704,8 +6937,8 @@ return -ENOENT; } - err = snd_card_create(index[dev], id[dev], - THIS_MODULE, sizeof(struct hdspm), &card); + err = snd_card_new(&pci->dev, index[dev], id[dev], + THIS_MODULE, sizeof(struct hdspm), &card); if (err < 0) return err; @@ -6714,8 +6947,6 @@ hdspm->dev = dev; hdspm->pci = pci; - snd_card_set_dev(card, &pci->dev); - err = snd_hdspm_create(card, hdspm); if (err < 0) { snd_card_free(card); @@ -6751,7 +6982,6 @@ static void snd_hdspm_remove(struct pci_dev *pci) { snd_card_free(pci_get_drvdata(pci)); - pci_set_drvdata(pci, NULL); } static struct pci_driver hdspm_driver = {