[PATCH 0/9] ALSA: emu10k1: improvements related to the switchable word clock of E-MU cards
Oswald Buddenhagen (9): ALSA: emu10k1: split off E-MU fallback clock from clock source ALSA: emu10k1: make available E-MU clock sources card-specific ALSA: emu10k1: query rate of external clock sources on E-MU cards ALSA: emu10k1: fix sample rates for E-MU cards at 44.1 kHz word clock ALSA: emu10k1: fix synthesizer pitch for E-MU cards at 44.1 kHz ALSA: timer: minimize open-coded access to hw.resolution ALSA: emu10k1: fix timer for E-MU cards at 44.1 kHz word clock ALSA: emu10k1: add support for 12 kHz capture on Audigy ALSA: emu10k1: actually show some S/PDIF status in /proc for E-MU cards
include/sound/emu10k1.h | 11 +- include/sound/emux_synth.h | 2 +- sound/core/timer.c | 18 +- sound/pci/emu10k1/emu10k1_callback.c | 10 ++ sound/pci/emu10k1/emu10k1_main.c | 7 +- sound/pci/emu10k1/emu10k1_synth.c | 1 - sound/pci/emu10k1/emumixer.c | 242 ++++++++++++++++----------- sound/pci/emu10k1/emupcm.c | 125 +++++++------- sound/pci/emu10k1/emuproc.c | 51 +++--- sound/pci/emu10k1/io.c | 72 ++++++++ sound/pci/emu10k1/timer.c | 20 ++- sound/synth/emux/emux_synth.c | 3 +- 12 files changed, 374 insertions(+), 188 deletions(-)
So far, we set the fallback as a side effect of setting the source. But the fallback makes no sense at all when an internal clock is selected. Defaulting to 48k for S/PDIF & ADAT makes sense, but as that is the global default and we're not changing it automatically any more, it's just fine to leave it entirely to the explicit setting.
This changes the name of the pre-existing control to something more appropriate (regardless of the split), so users will need to adjust their mixer settings.
Signed-off-by: Oswald Buddenhagen oswald.buddenhagen@gmx.de --- include/sound/emu10k1.h | 3 +- sound/pci/emu10k1/emu10k1_main.c | 3 +- sound/pci/emu10k1/emumixer.c | 89 +++++++++++++++++++++++--------- sound/pci/emu10k1/emupcm.c | 4 +- 4 files changed, 72 insertions(+), 27 deletions(-)
diff --git a/include/sound/emu10k1.h b/include/sound/emu10k1.h index cc0151e7c828..59e79ea1f75e 100644 --- a/include/sound/emu10k1.h +++ b/include/sound/emu10k1.h @@ -1668,7 +1668,8 @@ struct snd_emu1010 { unsigned char input_source[NUM_INPUT_DESTS]; unsigned int adc_pads; /* bit mask */ unsigned int dac_pads; /* bit mask */ - unsigned int internal_clock; /* 44100 or 48000 */ + unsigned int clock_source; + unsigned int clock_fallback; unsigned int optical_in; /* 0:SPDIF, 1:ADAT */ unsigned int optical_out; /* 0:SPDIF, 1:ADAT */ struct delayed_work firmware_work; diff --git a/sound/pci/emu10k1/emu10k1_main.c b/sound/pci/emu10k1/emu10k1_main.c index 65207ef689cb..2aa11d70e285 100644 --- a/sound/pci/emu10k1/emu10k1_main.c +++ b/sound/pci/emu10k1/emu10k1_main.c @@ -900,7 +900,8 @@ static int snd_emu10k1_emu1010_init(struct snd_emu10k1 *emu) /* IRQ Enable: All off */ snd_emu1010_fpga_write(emu, EMU_HANA_IRQ_ENABLE, 0x00);
- emu->emu1010.internal_clock = 1; /* 48000 */ + emu->emu1010.clock_source = 1; /* 48000 */ + emu->emu1010.clock_fallback = 1; /* 48000 */ /* Default WCLK set to 48kHz. */ snd_emu1010_fpga_write(emu, EMU_HANA_DEFCLOCK, EMU_HANA_DEFCLOCK_48K); /* Word Clock source, Internal 48kHz x1 */ diff --git a/sound/pci/emu10k1/emumixer.c b/sound/pci/emu10k1/emumixer.c index 20a0b3afc8a5..5b50d9c07a60 100644 --- a/sound/pci/emu10k1/emumixer.c +++ b/sound/pci/emu10k1/emumixer.c @@ -888,46 +888,44 @@ static const struct snd_emu1010_pads_info emu1010_pads_info[] = { };
-static int snd_emu1010_internal_clock_info(struct snd_kcontrol *kcontrol, +static int snd_emu1010_clock_source_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) { static const char * const texts[4] = { "44100", "48000", "SPDIF", "ADAT" }; return snd_ctl_enum_info(uinfo, 1, 4, texts); }
-static int snd_emu1010_internal_clock_get(struct snd_kcontrol *kcontrol, +static int snd_emu1010_clock_source_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
- ucontrol->value.enumerated.item[0] = emu->emu1010.internal_clock; + ucontrol->value.enumerated.item[0] = emu->emu1010.clock_source; return 0; }
-static int snd_emu1010_internal_clock_put(struct snd_kcontrol *kcontrol, +static int snd_emu1010_clock_source_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol); unsigned int val; int change = 0;
val = ucontrol->value.enumerated.item[0] ; /* Limit: uinfo->value.enumerated.items = 4; */ if (val >= 4) return -EINVAL; - change = (emu->emu1010.internal_clock != val); + change = (emu->emu1010.clock_source != val); if (change) { - emu->emu1010.internal_clock = val; + emu->emu1010.clock_source = val; switch (val) { case 0: /* 44100 */ /* Mute all */ snd_emu1010_fpga_write(emu, EMU_HANA_UNMUTE, EMU_MUTE ); - /* Default fallback clock 44.1kHz */ - snd_emu1010_fpga_write(emu, EMU_HANA_DEFCLOCK, EMU_HANA_DEFCLOCK_44_1K ); /* Word Clock source, Internal 44.1kHz x1 */ snd_emu1010_fpga_write(emu, EMU_HANA_WCLOCK, EMU_HANA_WCLOCK_INT_44_1K | EMU_HANA_WCLOCK_1X ); @@ -943,8 +941,6 @@ static int snd_emu1010_internal_clock_put(struct snd_kcontrol *kcontrol, /* 48000 */ /* Mute all */ snd_emu1010_fpga_write(emu, EMU_HANA_UNMUTE, EMU_MUTE ); - /* Default fallback clock 48kHz */ - snd_emu1010_fpga_write(emu, EMU_HANA_DEFCLOCK, EMU_HANA_DEFCLOCK_48K ); /* Word Clock source, Internal 48kHz x1 */ snd_emu1010_fpga_write(emu, EMU_HANA_WCLOCK, EMU_HANA_WCLOCK_INT_48K | EMU_HANA_WCLOCK_1X ); @@ -960,8 +956,6 @@ static int snd_emu1010_internal_clock_put(struct snd_kcontrol *kcontrol, case 2: /* Take clock from S/PDIF IN */ /* Mute all */ snd_emu1010_fpga_write(emu, EMU_HANA_UNMUTE, EMU_MUTE ); - /* Default fallback clock 48kHz */ - snd_emu1010_fpga_write(emu, EMU_HANA_DEFCLOCK, EMU_HANA_DEFCLOCK_48K ); /* Word Clock source, sync to S/PDIF input */ snd_emu1010_fpga_write(emu, EMU_HANA_WCLOCK, EMU_HANA_WCLOCK_HANA_SPDIF_IN | EMU_HANA_WCLOCK_1X ); @@ -979,8 +973,6 @@ static int snd_emu1010_internal_clock_put(struct snd_kcontrol *kcontrol, /* Take clock from ADAT IN */ /* Mute all */ snd_emu1010_fpga_write(emu, EMU_HANA_UNMUTE, EMU_MUTE ); - /* Default fallback clock 48kHz */ - snd_emu1010_fpga_write(emu, EMU_HANA_DEFCLOCK, EMU_HANA_DEFCLOCK_48K ); /* Word Clock source, sync to ADAT input */ snd_emu1010_fpga_write(emu, EMU_HANA_WCLOCK, EMU_HANA_WCLOCK_HANA_ADAT_IN | EMU_HANA_WCLOCK_1X ); @@ -999,15 +991,62 @@ static int snd_emu1010_internal_clock_put(struct snd_kcontrol *kcontrol, return change; }
-static const struct snd_kcontrol_new snd_emu1010_internal_clock = +static const struct snd_kcontrol_new snd_emu1010_clock_source = { - .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - .name = "Clock Internal Rate", - .count = 1, - .info = snd_emu1010_internal_clock_info, - .get = snd_emu1010_internal_clock_get, - .put = snd_emu1010_internal_clock_put + .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "Clock Source", + .count = 1, + .info = snd_emu1010_clock_source_info, + .get = snd_emu1010_clock_source_get, + .put = snd_emu1010_clock_source_put +}; + +static int snd_emu1010_clock_fallback_info(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_info *uinfo) +{ + static const char * const texts[2] = { + "44100", "48000" + }; + + return snd_ctl_enum_info(uinfo, 1, 2, texts); +} + +static int snd_emu1010_clock_fallback_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol); + + ucontrol->value.enumerated.item[0] = emu->emu1010.clock_fallback; + return 0; +} + +static int snd_emu1010_clock_fallback_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol); + unsigned int val = ucontrol->value.enumerated.item[0]; + int change; + + if (val >= 2) + return -EINVAL; + change = (emu->emu1010.clock_fallback != val); + if (change) { + emu->emu1010.clock_fallback = val; + snd_emu1010_fpga_write(emu, EMU_HANA_DEFCLOCK, 1 - val); + } + return change; +} + +static const struct snd_kcontrol_new snd_emu1010_clock_fallback = +{ + .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "Clock Fallback", + .count = 1, + .info = snd_emu1010_clock_fallback_info, + .get = snd_emu1010_clock_fallback_get, + .put = snd_emu1010_clock_fallback_put };
static int snd_emu1010_optical_out_info(struct snd_kcontrol *kcontrol, @@ -2297,7 +2336,11 @@ int snd_emu10k1_mixer(struct snd_emu10k1 *emu, snd_emu1010_apply_sources(emu);
err = snd_ctl_add(card, - snd_ctl_new1(&snd_emu1010_internal_clock, emu)); + snd_ctl_new1(&snd_emu1010_clock_source, emu)); + if (err < 0) + return err; + err = snd_ctl_add(card, + snd_ctl_new1(&snd_emu1010_clock_fallback, emu)); if (err < 0) return err;
diff --git a/sound/pci/emu10k1/emupcm.c b/sound/pci/emu10k1/emupcm.c index 550caefa0ce4..fab537788587 100644 --- a/sound/pci/emu10k1/emupcm.c +++ b/sound/pci/emu10k1/emupcm.c @@ -1185,7 +1185,7 @@ static int snd_emu10k1_playback_open(struct snd_pcm_substream *substream) kfree(epcm); return err; } - if (emu->card_capabilities->emu_model && emu->emu1010.internal_clock == 0) + if (emu->card_capabilities->emu_model && emu->emu1010.clock_source == 0) sample_rate = 44100; else sample_rate = 48000; @@ -1335,7 +1335,7 @@ static int snd_emu10k1_capture_efx_open(struct snd_pcm_substream *substream) * but we don't exceed 16 channels anyway. */ #if 1 - switch (emu->emu1010.internal_clock) { + switch (emu->emu1010.clock_source) { case 0: /* For 44.1kHz */ runtime->hw.rates = SNDRV_PCM_RATE_44100;
The actually available clock sources depend on the available audio input ports and dedicated clock input ports.
This includes refactoring the code to be data-driven to remain manageable.
Signed-off-by: Oswald Buddenhagen oswald.buddenhagen@gmx.de --- include/sound/emu10k1.h | 2 + sound/pci/emu10k1/emu10k1_main.c | 4 +- sound/pci/emu10k1/emumixer.c | 153 ++++++++++++++++--------------- sound/pci/emu10k1/io.c | 23 +++++ 4 files changed, 107 insertions(+), 75 deletions(-)
diff --git a/include/sound/emu10k1.h b/include/sound/emu10k1.h index 59e79ea1f75e..703ef441bb2a 100644 --- a/include/sound/emu10k1.h +++ b/include/sound/emu10k1.h @@ -1668,6 +1668,7 @@ struct snd_emu1010 { unsigned char input_source[NUM_INPUT_DESTS]; unsigned int adc_pads; /* bit mask */ unsigned int dac_pads; /* bit mask */ + unsigned int wclock; /* Cached register value */ unsigned int clock_source; unsigned int clock_fallback; unsigned int optical_in; /* 0:SPDIF, 1:ADAT */ @@ -1824,6 +1825,7 @@ void snd_emu1010_fpga_write(struct snd_emu10k1 *emu, u32 reg, u32 value); void snd_emu1010_fpga_read(struct snd_emu10k1 *emu, u32 reg, u32 *value); void snd_emu1010_fpga_link_dst_src_write(struct snd_emu10k1 *emu, u32 dst, u32 src); u32 snd_emu1010_fpga_link_dst_src_read(struct snd_emu10k1 *emu, u32 dst); +void snd_emu1010_update_clock(struct snd_emu10k1 *emu); unsigned int snd_emu10k1_efx_read(struct snd_emu10k1 *emu, unsigned int pc); void snd_emu10k1_intr_enable(struct snd_emu10k1 *emu, unsigned int intrenb); void snd_emu10k1_intr_disable(struct snd_emu10k1 *emu, unsigned int intrenb); diff --git a/sound/pci/emu10k1/emu10k1_main.c b/sound/pci/emu10k1/emu10k1_main.c index 2aa11d70e285..58ed72de6403 100644 --- a/sound/pci/emu10k1/emu10k1_main.c +++ b/sound/pci/emu10k1/emu10k1_main.c @@ -905,10 +905,10 @@ static int snd_emu10k1_emu1010_init(struct snd_emu10k1 *emu) /* Default WCLK set to 48kHz. */ snd_emu1010_fpga_write(emu, EMU_HANA_DEFCLOCK, EMU_HANA_DEFCLOCK_48K); /* Word Clock source, Internal 48kHz x1 */ + emu->emu1010.wclock = EMU_HANA_WCLOCK_INT_48K; snd_emu1010_fpga_write(emu, EMU_HANA_WCLOCK, EMU_HANA_WCLOCK_INT_48K); /* snd_emu1010_fpga_write(emu, EMU_HANA_WCLOCK, EMU_HANA_WCLOCK_INT_48K | EMU_HANA_WCLOCK_4X); */ - /* Audio Dock LEDs. */ - snd_emu1010_fpga_write(emu, EMU_HANA_DOCK_LEDS_2, EMU_HANA_DOCK_LEDS_2_LOCK | EMU_HANA_DOCK_LEDS_2_48K); + snd_emu1010_update_clock(emu);
// The routes are all set to EMU_SRC_SILENCE due to the reset, // so it is safe to simply enable the outputs. diff --git a/sound/pci/emu10k1/emumixer.c b/sound/pci/emu10k1/emumixer.c index 5b50d9c07a60..f9500cd50a4b 100644 --- a/sound/pci/emu10k1/emumixer.c +++ b/sound/pci/emu10k1/emumixer.c @@ -887,15 +887,79 @@ static const struct snd_emu1010_pads_info emu1010_pads_info[] = { }, };
+static const char * const emu1010_clock_texts[] = { + "44100", "48000", "SPDIF", "ADAT", "Dock", "BNC" +}; + +static const u8 emu1010_clock_vals[] = { + EMU_HANA_WCLOCK_INT_44_1K, + EMU_HANA_WCLOCK_INT_48K, + EMU_HANA_WCLOCK_HANA_SPDIF_IN, + EMU_HANA_WCLOCK_HANA_ADAT_IN, + EMU_HANA_WCLOCK_2ND_HANA, + EMU_HANA_WCLOCK_SYNC_BNC, +}; + +static const char * const emu0404_clock_texts[] = { + "44100", "48000", "SPDIF", "BNC" +}; + +static const u8 emu0404_clock_vals[] = { + EMU_HANA_WCLOCK_INT_44_1K, + EMU_HANA_WCLOCK_INT_48K, + EMU_HANA_WCLOCK_HANA_SPDIF_IN, + EMU_HANA_WCLOCK_SYNC_BNC, +}; + +struct snd_emu1010_clock_info { + const char * const *texts; + const u8 *vals; + unsigned num; +}; + +static const struct snd_emu1010_clock_info emu1010_clock_info[] = { + { + // rev1 1010 + .texts = emu1010_clock_texts, + .vals = emu1010_clock_vals, + .num = ARRAY_SIZE(emu1010_clock_vals), + }, + { + // rev2 1010 + .texts = emu1010_clock_texts, + .vals = emu1010_clock_vals, + .num = ARRAY_SIZE(emu1010_clock_vals) - 1, + }, + { + // 1616(m) CardBus + .texts = emu1010_clock_texts, + // TODO: determine what is actually available. + // Pedantically, *every* source comes from the 2nd FPGA, as the + // card itself has no own (digital) audio ports. The user manual + // claims that ADAT and S/PDIF clock sources are separate, which + // can mean two things: either E-MU mapped the dock's sources to + // the primary ones, or they determine the meaning of the "Dock" + // source depending on how the ports are actually configured + // (which the 2nd FPGA must be doing anyway). + .vals = emu1010_clock_vals, + .num = ARRAY_SIZE(emu1010_clock_vals), + }, + { + // 0404 + .texts = emu0404_clock_texts, + .vals = emu0404_clock_vals, + .num = ARRAY_SIZE(emu0404_clock_vals), + }, +};
static int snd_emu1010_clock_source_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) { - static const char * const texts[4] = { - "44100", "48000", "SPDIF", "ADAT" - }; + struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol); + const struct snd_emu1010_clock_info *emu_ci = + &emu1010_clock_info[emu1010_idx(emu)]; - return snd_ctl_enum_info(uinfo, 1, 4, texts); + return snd_ctl_enum_info(uinfo, 1, emu_ci->num, emu_ci->texts); }
static int snd_emu1010_clock_source_get(struct snd_kcontrol *kcontrol, @@ -911,84 +975,27 @@ static int snd_emu1010_clock_source_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol); + const struct snd_emu1010_clock_info *emu_ci = + &emu1010_clock_info[emu1010_idx(emu)]; unsigned int val; int change = 0;
val = ucontrol->value.enumerated.item[0] ; - /* Limit: uinfo->value.enumerated.items = 4; */ - if (val >= 4) + if (val >= emu_ci->num) return -EINVAL; change = (emu->emu1010.clock_source != val); if (change) { emu->emu1010.clock_source = val; - switch (val) { - case 0: - /* 44100 */ - /* Mute all */ - snd_emu1010_fpga_write(emu, EMU_HANA_UNMUTE, EMU_MUTE ); - /* Word Clock source, Internal 44.1kHz x1 */ - snd_emu1010_fpga_write(emu, EMU_HANA_WCLOCK, - EMU_HANA_WCLOCK_INT_44_1K | EMU_HANA_WCLOCK_1X ); - /* Set LEDs on Audio Dock */ - snd_emu1010_fpga_write(emu, EMU_HANA_DOCK_LEDS_2, - EMU_HANA_DOCK_LEDS_2_44K | EMU_HANA_DOCK_LEDS_2_LOCK ); - /* Allow DLL to settle */ - msleep(10); - /* Unmute all */ - snd_emu1010_fpga_write(emu, EMU_HANA_UNMUTE, EMU_UNMUTE ); - break; - case 1: - /* 48000 */ - /* Mute all */ - snd_emu1010_fpga_write(emu, EMU_HANA_UNMUTE, EMU_MUTE ); - /* Word Clock source, Internal 48kHz x1 */ - snd_emu1010_fpga_write(emu, EMU_HANA_WCLOCK, - EMU_HANA_WCLOCK_INT_48K | EMU_HANA_WCLOCK_1X ); - /* Set LEDs on Audio Dock */ - snd_emu1010_fpga_write(emu, EMU_HANA_DOCK_LEDS_2, - EMU_HANA_DOCK_LEDS_2_48K | EMU_HANA_DOCK_LEDS_2_LOCK ); - /* Allow DLL to settle */ - msleep(10); - /* Unmute all */ - snd_emu1010_fpga_write(emu, EMU_HANA_UNMUTE, EMU_UNMUTE ); - break; - - case 2: /* Take clock from S/PDIF IN */ - /* Mute all */ - snd_emu1010_fpga_write(emu, EMU_HANA_UNMUTE, EMU_MUTE ); - /* Word Clock source, sync to S/PDIF input */ - snd_emu1010_fpga_write(emu, EMU_HANA_WCLOCK, - EMU_HANA_WCLOCK_HANA_SPDIF_IN | EMU_HANA_WCLOCK_1X ); - /* Set LEDs on Audio Dock */ - snd_emu1010_fpga_write(emu, EMU_HANA_DOCK_LEDS_2, - EMU_HANA_DOCK_LEDS_2_EXT | EMU_HANA_DOCK_LEDS_2_LOCK ); - /* FIXME: We should set EMU_HANA_DOCK_LEDS_2_LOCK only when clock signal is present and valid */ - /* Allow DLL to settle */ - msleep(10); - /* Unmute all */ - snd_emu1010_fpga_write(emu, EMU_HANA_UNMUTE, EMU_UNMUTE ); - break; - - case 3: - /* Take clock from ADAT IN */ - /* Mute all */ - snd_emu1010_fpga_write(emu, EMU_HANA_UNMUTE, EMU_MUTE ); - /* Word Clock source, sync to ADAT input */ - snd_emu1010_fpga_write(emu, EMU_HANA_WCLOCK, - EMU_HANA_WCLOCK_HANA_ADAT_IN | EMU_HANA_WCLOCK_1X ); - /* Set LEDs on Audio Dock */ - snd_emu1010_fpga_write(emu, EMU_HANA_DOCK_LEDS_2, EMU_HANA_DOCK_LEDS_2_EXT | EMU_HANA_DOCK_LEDS_2_LOCK ); - /* FIXME: We should set EMU_HANA_DOCK_LEDS_2_LOCK only when clock signal is present and valid */ - /* Allow DLL to settle */ - msleep(10); - /* Unmute all */ - snd_emu1010_fpga_write(emu, EMU_HANA_UNMUTE, EMU_UNMUTE ); - - - break; - } + emu->emu1010.wclock = emu_ci->vals[val]; + + snd_emu1010_fpga_write(emu, EMU_HANA_UNMUTE, EMU_MUTE); + snd_emu1010_fpga_write(emu, EMU_HANA_WCLOCK, emu->emu1010.wclock); + msleep(10); // Allow DLL to settle + snd_emu1010_fpga_write(emu, EMU_HANA_UNMUTE, EMU_UNMUTE); + + snd_emu1010_update_clock(emu); } - return change; + return change; }
static const struct snd_kcontrol_new snd_emu1010_clock_source = diff --git a/sound/pci/emu10k1/io.c b/sound/pci/emu10k1/io.c index abe69ae40499..e7a44443023a 100644 --- a/sound/pci/emu10k1/io.c +++ b/sound/pci/emu10k1/io.c @@ -357,6 +357,29 @@ u32 snd_emu1010_fpga_link_dst_src_read(struct snd_emu10k1 *emu, u32 dst) return (hi << 8) | lo; }
+void snd_emu1010_update_clock(struct snd_emu10k1 *emu) +{ + u32 leds; + + switch (emu->emu1010.wclock) { + case EMU_HANA_WCLOCK_INT_44_1K | EMU_HANA_WCLOCK_1X: + leds = EMU_HANA_DOCK_LEDS_2_44K; + break; + case EMU_HANA_WCLOCK_INT_48K | EMU_HANA_WCLOCK_1X: + leds = EMU_HANA_DOCK_LEDS_2_48K; + break; + default: + leds = EMU_HANA_DOCK_LEDS_2_EXT; + break; + } + + // FIXME: this should probably represent the AND of all currently + // used sources' lock status. But we don't know how to get that ... + leds |= EMU_HANA_DOCK_LEDS_2_LOCK; + + snd_emu1010_fpga_write(emu, EMU_HANA_DOCK_LEDS_2, leds); +} + void snd_emu10k1_intr_enable(struct snd_emu10k1 *emu, unsigned int intrenb) { unsigned long flags;
The value isn't used yet; the subsequent commits will do that.
This ignores the existence of rates above 48 kHz, which is fine, as the hardware will just switch to the fallback clock source when fed with a rate which is incompatible with the base clock multiplier, which currently is always x1.
The sample rate display in /proc spdif-in is adjusted to reflect our understanding of the input rates.
This is tested only with an 0404b card without sync card, so there is a lot of room for improvement.
Signed-off-by: Oswald Buddenhagen oswald.buddenhagen@gmx.de
---
FIXME: needs a lot of testing to figure out things for real: 0404, 1010, 1010b, and 1616 hardware, with adat, s/pdif on 1010 and dock, and bnc sync. what are the lock status and the displayed rates with no signal, good signal async to internal clock, and synced signal? test s/pdif at least with 48 & 96 khz (192 works on 1010b & 1616m cards on the RCA port). --- include/sound/emu10k1.h | 5 ++++ sound/pci/emu10k1/emuproc.c | 43 ++++++++++++++++--------------- sound/pci/emu10k1/io.c | 51 ++++++++++++++++++++++++++++++++++++- 3 files changed, 78 insertions(+), 21 deletions(-)
diff --git a/include/sound/emu10k1.h b/include/sound/emu10k1.h index 703ef441bb2a..d64cf1697586 100644 --- a/include/sound/emu10k1.h +++ b/include/sound/emu10k1.h @@ -1110,6 +1110,9 @@ SUB_REG_NC(A_EHC, A_I2S_CAPTURE_RATE, 0x00000e00) /* This sets the capture PCM #define EMU_DOCK_BOARD_ID0 0x00 /* ID bit 0 */ #define EMU_DOCK_BOARD_ID1 0x03 /* ID bit 1 */
+// The actual code disagrees about the bit width of the registers - +// the formula used is freq = 0x1770000 / (((X_HI << 5) | X_LO) + 1) + #define EMU_HANA_WC_SPDIF_HI 0x28 /* 0xxxxxx 6 bit SPDIF IN Word clock, upper 6 bits */ #define EMU_HANA_WC_SPDIF_LO 0x29 /* 0xxxxxx 6 bit SPDIF IN Word clock, lower 6 bits */
@@ -1669,6 +1672,7 @@ struct snd_emu1010 { unsigned int adc_pads; /* bit mask */ unsigned int dac_pads; /* bit mask */ unsigned int wclock; /* Cached register value */ + unsigned int word_clock; /* Cached effective value */ unsigned int clock_source; unsigned int clock_fallback; unsigned int optical_in; /* 0:SPDIF, 1:ADAT */ @@ -1825,6 +1829,7 @@ void snd_emu1010_fpga_write(struct snd_emu10k1 *emu, u32 reg, u32 value); void snd_emu1010_fpga_read(struct snd_emu10k1 *emu, u32 reg, u32 *value); void snd_emu1010_fpga_link_dst_src_write(struct snd_emu10k1 *emu, u32 dst, u32 src); u32 snd_emu1010_fpga_link_dst_src_read(struct snd_emu10k1 *emu, u32 dst); +int snd_emu1010_get_raw_rate(struct snd_emu10k1 *emu, u8 src); void snd_emu1010_update_clock(struct snd_emu10k1 *emu); unsigned int snd_emu10k1_efx_read(struct snd_emu10k1 *emu, unsigned int pc); void snd_emu10k1_intr_enable(struct snd_emu10k1 *emu, unsigned int intrenb); diff --git a/sound/pci/emu10k1/emuproc.c b/sound/pci/emu10k1/emuproc.c index ca7b4dddbea8..993b35362499 100644 --- a/sound/pci/emu10k1/emuproc.c +++ b/sound/pci/emu10k1/emuproc.c @@ -168,29 +168,32 @@ static void snd_emu10k1_proc_spdif_read(struct snd_info_entry *entry, struct snd_emu10k1 *emu = entry->private_data; u32 value; u32 value2; - u32 rate;
if (emu->card_capabilities->emu_model) { - if (!emu->card_capabilities->no_adat) { - snd_emu1010_fpga_read(emu, 0x38, &value); - if ((value & 0x1) == 0) { - snd_emu1010_fpga_read(emu, 0x2a, &value); - snd_emu1010_fpga_read(emu, 0x2b, &value2); - rate = 0x1770000 / (((value << 5) | value2)+1); - snd_iprintf(buffer, "ADAT Locked : %u\n", rate); - } else { - snd_iprintf(buffer, "ADAT Unlocked\n"); - } - } - snd_emu1010_fpga_read(emu, 0x20, &value); - if ((value & 0x4) == 0) { - snd_emu1010_fpga_read(emu, 0x28, &value); - snd_emu1010_fpga_read(emu, 0x29, &value2); - rate = 0x1770000 / (((value << 5) | value2)+1); - snd_iprintf(buffer, "SPDIF Locked : %d\n", rate); - } else { - snd_iprintf(buffer, "SPDIF Unlocked\n"); + // This represents the S/PDIF lock status on 0404b, which is + // kinda weird and unhelpful, because monitoring it via IRQ is + // impractical (one gets an IRQ flood as long as it is desynced). + snd_emu1010_fpga_read(emu, EMU_HANA_IRQ_STATUS, &value); + snd_iprintf(buffer, "Lock status 1: %#x\n", value & 0x10); + + // Bit 0x1 in LO being 0 is supposedly for ADAT lock. + // The registers are always all zero on 0404b. + snd_emu1010_fpga_read(emu, EMU_HANA_LOCK_STS_LO, &value); + snd_emu1010_fpga_read(emu, EMU_HANA_LOCK_STS_HI, &value2); + snd_iprintf(buffer, "Lock status 2: %#x %#x\n", value, value2); + + snd_iprintf(buffer, "S/PDIF rate: %dHz\n", + snd_emu1010_get_raw_rate(emu, EMU_HANA_WCLOCK_HANA_SPDIF_IN)); + if (emu->card_capabilities->emu_model != EMU_MODEL_EMU0404) { + snd_iprintf(buffer, "ADAT rate: %dHz\n", + snd_emu1010_get_raw_rate(emu, EMU_HANA_WCLOCK_HANA_ADAT_IN)); + snd_iprintf(buffer, "Dock rate: %dHz\n", + snd_emu1010_get_raw_rate(emu, EMU_HANA_WCLOCK_2ND_HANA)); } + if (emu->card_capabilities->emu_model == EMU_MODEL_EMU0404 || + emu->card_capabilities->emu_model == EMU_MODEL_EMU1010) + snd_iprintf(buffer, "BNC rate: %dHz\n", + snd_emu1010_get_raw_rate(emu, EMU_HANA_WCLOCK_SYNC_BNC)); } else { snd_emu10k1_proc_spdif_status(emu, buffer, "CD-ROM S/PDIF In", CDCS, CDSRCS); snd_emu10k1_proc_spdif_status(emu, buffer, "Optical or Coax S/PDIF In", GPSCS, GPSRCS); diff --git a/sound/pci/emu10k1/io.c b/sound/pci/emu10k1/io.c index e7a44443023a..a0d66ce3ee83 100644 --- a/sound/pci/emu10k1/io.c +++ b/sound/pci/emu10k1/io.c @@ -357,21 +357,70 @@ u32 snd_emu1010_fpga_link_dst_src_read(struct snd_emu10k1 *emu, u32 dst) return (hi << 8) | lo; }
+int snd_emu1010_get_raw_rate(struct snd_emu10k1 *emu, u8 src) +{ + u32 reg_lo, reg_hi, value, value2; + + switch (src) { + case EMU_HANA_WCLOCK_HANA_SPDIF_IN: + snd_emu1010_fpga_read(emu, EMU_HANA_SPDIF_MODE, &value); + if (value & EMU_HANA_SPDIF_MODE_RX_INVALID) + return 0; + reg_lo = EMU_HANA_WC_SPDIF_LO; + reg_hi = EMU_HANA_WC_SPDIF_HI; + break; + case EMU_HANA_WCLOCK_HANA_ADAT_IN: + reg_lo = EMU_HANA_WC_ADAT_LO; + reg_hi = EMU_HANA_WC_ADAT_HI; + break; + case EMU_HANA_WCLOCK_SYNC_BNC: + reg_lo = EMU_HANA_WC_BNC_LO; + reg_hi = EMU_HANA_WC_BNC_HI; + break; + case EMU_HANA_WCLOCK_2ND_HANA: + reg_lo = EMU_HANA2_WC_SPDIF_LO; + reg_hi = EMU_HANA2_WC_SPDIF_HI; + break; + default: + return 0; + } + snd_emu1010_fpga_read(emu, reg_hi, &value); + snd_emu1010_fpga_read(emu, reg_lo, &value2); + // FIXME: The /4 is valid for 0404b, but contradicts all other info. + return 0x1770000 / 4 / (((value << 5) | value2) + 1); +} + void snd_emu1010_update_clock(struct snd_emu10k1 *emu) { + int clock; u32 leds;
switch (emu->emu1010.wclock) { case EMU_HANA_WCLOCK_INT_44_1K | EMU_HANA_WCLOCK_1X: + clock = 44100; leds = EMU_HANA_DOCK_LEDS_2_44K; break; case EMU_HANA_WCLOCK_INT_48K | EMU_HANA_WCLOCK_1X: + clock = 48000; leds = EMU_HANA_DOCK_LEDS_2_48K; break; default: - leds = EMU_HANA_DOCK_LEDS_2_EXT; + clock = snd_emu1010_get_raw_rate( + emu, emu->emu1010.wclock & EMU_HANA_WCLOCK_SRC_MASK); + // The raw rate reading is rather coarse (it cannot accurately + // represent 44.1 kHz) and fluctuates slightly. Luckily, the + // clock comes from digital inputs, which use standardized rates. + // So we round to the closest standard rate and ignore discrepancies. + if (clock < 46000) { + clock = 44100; + leds = EMU_HANA_DOCK_LEDS_2_EXT | EMU_HANA_DOCK_LEDS_2_44K; + } else { + clock = 48000; + leds = EMU_HANA_DOCK_LEDS_2_EXT | EMU_HANA_DOCK_LEDS_2_48K; + } break; } + emu->emu1010.word_clock = clock;
// FIXME: this should probably represent the AND of all currently // used sources' lock status. But we don't know how to get that ...
Now that we know the actual word clock, we can: - Put the resulting rate into the hardware info - At 44.1 kHz word clock shift the rate for the pitch calculations, which presume a 48 kHz word clock
Signed-off-by: Oswald Buddenhagen oswald.buddenhagen@gmx.de --- include/sound/emu10k1.h | 1 + sound/pci/emu10k1/emupcm.c | 112 ++++++++++++++++++------------------- 2 files changed, 56 insertions(+), 57 deletions(-)
diff --git a/include/sound/emu10k1.h b/include/sound/emu10k1.h index d64cf1697586..386a5f3be3e0 100644 --- a/include/sound/emu10k1.h +++ b/include/sound/emu10k1.h @@ -1495,6 +1495,7 @@ struct snd_emu10k1_pcm { unsigned short first_ptr; snd_pcm_uframes_t resume_pos; struct snd_util_memblk *memblk; + unsigned int pitch_target; unsigned int start_addr; unsigned int ccca_start_addr; unsigned int capture_ipr; /* interrupt acknowledge mask */ diff --git a/sound/pci/emu10k1/emupcm.c b/sound/pci/emu10k1/emupcm.c index fab537788587..3ef9130a9577 100644 --- a/sound/pci/emu10k1/emupcm.c +++ b/sound/pci/emu10k1/emupcm.c @@ -195,6 +195,33 @@ static unsigned int snd_emu10k1_audigy_capture_rate_reg(unsigned int rate) } }
+static void snd_emu10k1_constrain_capture_rates(struct snd_emu10k1 *emu, + struct snd_pcm_runtime *runtime) +{ + if (emu->card_capabilities->emu_model && + emu->emu1010.word_clock == 44100) { + // This also sets the rate constraint by deleting SNDRV_PCM_RATE_KNOT + runtime->hw.rates = SNDRV_PCM_RATE_11025 | \ + SNDRV_PCM_RATE_22050 | \ + SNDRV_PCM_RATE_44100; + runtime->hw.rate_min = 11025; + runtime->hw.rate_max = 44100; + return; + } + snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_RATE, + &hw_constraints_capture_rates); +} + +static void snd_emu1010_constrain_efx_rate(struct snd_emu10k1 *emu, + struct snd_pcm_runtime *runtime) +{ + int rate; + + rate = emu->emu1010.word_clock; + runtime->hw.rate_min = runtime->hw.rate_max = rate; + runtime->hw.rates = snd_pcm_rate_to_rate_bit(rate); +} + static unsigned int emu10k1_calc_pitch_target(unsigned int rate) { unsigned int pitch_target; @@ -251,29 +278,22 @@ static void snd_emu10k1_pcm_init_voice(struct snd_emu10k1 *emu, const unsigned char *send_routing, const unsigned char *send_amount) { - struct snd_pcm_substream *substream = evoice->epcm->substream; - struct snd_pcm_runtime *runtime = substream->runtime; unsigned int silent_page; int voice; - unsigned int pitch_target;
voice = evoice->number;
- if (emu->card_capabilities->emu_model) - pitch_target = PITCH_48000; /* Disable interpolators on emu1010 card */ - else - pitch_target = emu10k1_calc_pitch_target(runtime->rate); silent_page = ((unsigned int)emu->silent_page.addr << emu->address_mode) | (emu->address_mode ? MAP_PTI_MASK1 : MAP_PTI_MASK0); snd_emu10k1_ptr_write_multiple(emu, voice, // Not really necessary for the slave, but it doesn't hurt CPF, stereo ? CPF_STEREO_MASK : 0, // Assumption that PT is already 0 so no harm overwriting PTRX, (send_amount[0] << 8) | send_amount[1], // Stereo slaves don't need to have the addresses set, but it doesn't hurt DSL, end_addr | (send_amount[3] << 24), PSST, start_addr | (send_amount[2] << 24), - CCCA, emu10k1_select_interprom(pitch_target) | + CCCA, emu10k1_select_interprom(evoice->epcm->pitch_target) | (w_16 ? 0 : CCCA_8BITSELECT), // Clear filter delay memory Z1, 0, @@ -419,6 +439,13 @@ static int snd_emu10k1_playback_prepare(struct snd_pcm_substream *substream) bool w_16 = snd_pcm_format_width(runtime->format) == 16; bool stereo = runtime->channels == 2; unsigned int start_addr, end_addr; + unsigned int rate; + + rate = runtime->rate; + if (emu->card_capabilities->emu_model && + emu->emu1010.word_clock == 44100) + rate = rate * 480 / 441; + epcm->pitch_target = emu10k1_calc_pitch_target(rate);
start_addr = epcm->start_addr >> w_16; end_addr = start_addr + runtime->period_size; @@ -443,6 +470,8 @@ static int snd_emu10k1_efx_playback_prepare(struct snd_pcm_substream *substream) unsigned int extra_size, channel_size; unsigned int i;
+ epcm->pitch_target = PITCH_48000; + start_addr = epcm->start_addr >> 1; // 16-bit voices
extra_size = runtime->period_size; @@ -526,12 +555,16 @@ static int snd_emu10k1_capture_prepare(struct snd_pcm_substream *substream) epcm->capture_bs_val++; } if (epcm->type == CAPTURE_AC97ADC) { + unsigned rate = runtime->rate; + if (!(runtime->hw.rates & SNDRV_PCM_RATE_48000)) + rate = rate * 480 / 441; + epcm->capture_cr_val = emu->audigy ? A_ADCCR_LCHANENABLE : ADCCR_LCHANENABLE; if (runtime->channels > 1) epcm->capture_cr_val |= emu->audigy ? A_ADCCR_RCHANENABLE : ADCCR_RCHANENABLE; epcm->capture_cr_val |= emu->audigy ? - snd_emu10k1_audigy_capture_rate_reg(runtime->rate) : - snd_emu10k1_capture_rate_reg(runtime->rate); + snd_emu10k1_audigy_capture_rate_reg(rate) : + snd_emu10k1_capture_rate_reg(rate); } return 0; } @@ -670,19 +703,10 @@ static void snd_emu10k1_playback_commit_pitch(struct snd_emu10k1 *emu, static void snd_emu10k1_playback_trigger_voice(struct snd_emu10k1 *emu, struct snd_emu10k1_voice *evoice) { - struct snd_pcm_substream *substream; - struct snd_pcm_runtime *runtime; - unsigned int voice, pitch_target; + unsigned int voice;
- substream = evoice->epcm->substream; - runtime = substream->runtime; voice = evoice->number; - - if (emu->card_capabilities->emu_model) - pitch_target = PITCH_48000; /* Disable interpolators on emu1010 card */ - else - pitch_target = emu10k1_calc_pitch_target(runtime->rate); - snd_emu10k1_playback_commit_pitch(emu, voice, pitch_target << 16); + snd_emu10k1_playback_commit_pitch(emu, voice, evoice->epcm->pitch_target << 16); }
static void snd_emu10k1_playback_stop_voice(struct snd_emu10k1 *emu, @@ -1043,11 +1067,9 @@ static const struct snd_pcm_hardware snd_emu10k1_capture_efx = SNDRV_PCM_INFO_RESUME | SNDRV_PCM_INFO_MMAP_VALID), .formats = SNDRV_PCM_FMTBIT_S16_LE, - .rates = SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000 | - SNDRV_PCM_RATE_88200 | SNDRV_PCM_RATE_96000 | - SNDRV_PCM_RATE_176400 | SNDRV_PCM_RATE_192000, - .rate_min = 44100, - .rate_max = 192000, + .rates = SNDRV_PCM_RATE_48000, + .rate_min = 48000, + .rate_max = 48000, .channels_min = 1, .channels_max = 16, .buffer_bytes_max = (64*1024), @@ -1144,6 +1166,8 @@ static int snd_emu10k1_efx_playback_open(struct snd_pcm_substream *substream) runtime->private_data = epcm; runtime->private_free = snd_emu10k1_pcm_free_substream; runtime->hw = snd_emu10k1_efx_playback; + if (emu->card_capabilities->emu_model) + snd_emu1010_constrain_efx_rate(emu, runtime); err = snd_emu10k1_playback_set_constraints(runtime); if (err < 0) { kfree(epcm); @@ -1185,8 +1209,8 @@ static int snd_emu10k1_playback_open(struct snd_pcm_substream *substream) kfree(epcm); return err; } - if (emu->card_capabilities->emu_model && emu->emu1010.clock_source == 0) - sample_rate = 44100; + if (emu->card_capabilities->emu_model) + sample_rate = emu->emu1010.word_clock; else sample_rate = 48000; err = snd_pcm_hw_rule_noresample(runtime, sample_rate); @@ -1236,11 +1260,11 @@ static int snd_emu10k1_capture_open(struct snd_pcm_substream *substream) runtime->private_data = epcm; runtime->private_free = snd_emu10k1_pcm_free_substream; runtime->hw = snd_emu10k1_capture; + snd_emu10k1_constrain_capture_rates(emu, runtime); snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_BUFFER_BYTES, &hw_constraints_capture_buffer_sizes); emu->capture_interrupt = snd_emu10k1_pcm_ac97adc_interrupt; emu->pcm_capture_substream = substream; - snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_RATE, &hw_constraints_capture_rates); return 0; }
@@ -1313,51 +1337,25 @@ static int snd_emu10k1_capture_efx_open(struct snd_pcm_substream *substream) substream->runtime->private_data = epcm; substream->runtime->private_free = snd_emu10k1_pcm_free_substream; runtime->hw = snd_emu10k1_capture_efx; - runtime->hw.rates = SNDRV_PCM_RATE_48000; - runtime->hw.rate_min = runtime->hw.rate_max = 48000; if (emu->card_capabilities->emu_model) { - /* TODO - * SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000 | - * SNDRV_PCM_RATE_88200 | SNDRV_PCM_RATE_96000 | - * SNDRV_PCM_RATE_176400 | SNDRV_PCM_RATE_192000 - * rate_min = 44100, - * rate_max = 192000, - * Need to add mixer control to fix sample rate - * + snd_emu1010_constrain_efx_rate(emu, runtime); + /* * There are 32 mono channels of 16bits each. * 24bit Audio uses 2x channels over 16bit, * 96kHz uses 2x channels over 48kHz, * 192kHz uses 4x channels over 48kHz. * So, for 48kHz 24bit, one has 16 channels, * for 96kHz 24bit, one has 8 channels, * for 192kHz 24bit, one has 4 channels. * 1010rev2 and 1616(m) cards have double that, * but we don't exceed 16 channels anyway. */ -#if 1 - switch (emu->emu1010.clock_source) { - case 0: - /* For 44.1kHz */ - runtime->hw.rates = SNDRV_PCM_RATE_44100; - runtime->hw.rate_min = runtime->hw.rate_max = 44100; - break; - case 1: - /* For 48kHz */ - runtime->hw.rates = SNDRV_PCM_RATE_48000; - runtime->hw.rate_min = runtime->hw.rate_max = 48000; - break; - } -#endif #if 0 /* For 96kHz */ - runtime->hw.rates = SNDRV_PCM_RATE_96000; - runtime->hw.rate_min = runtime->hw.rate_max = 96000; runtime->hw.channels_min = runtime->hw.channels_max = 4; #endif #if 0 /* For 192kHz */ - runtime->hw.rates = SNDRV_PCM_RATE_192000; - runtime->hw.rate_min = runtime->hw.rate_max = 192000; runtime->hw.channels_min = runtime->hw.channels_max = 2; #endif runtime->hw.formats = SNDRV_PCM_FMTBIT_S32_LE;
This is only a very partial fix - the frequency-dependent envelope & LFO register values aren't adjusted.
But I'm not sure they were even correct at 48 kHz to start with, as most of them are precalculated by common code which assumes an EMU8K-specific 44.1 kHz word clock, and it seems somewhat unlikely that the hardware's register interpretation was adjusted to compensate for the different word clock.
In any case I'm not going to spend time on fixing that, as this code is unlikely to be actually used by anyone today.
Signed-off-by: Oswald Buddenhagen oswald.buddenhagen@gmx.de --- include/sound/emux_synth.h | 2 +- sound/pci/emu10k1/emu10k1_callback.c | 10 ++++++++++ sound/pci/emu10k1/emu10k1_synth.c | 1 - sound/synth/emux/emux_synth.c | 3 ++- 4 files changed, 13 insertions(+), 3 deletions(-)
diff --git a/include/sound/emux_synth.h b/include/sound/emux_synth.h index d499b68122a3..1cc530434b97 100644 --- a/include/sound/emux_synth.h +++ b/include/sound/emux_synth.h @@ -54,6 +54,7 @@ struct snd_emux_operators { #if IS_ENABLED(CONFIG_SND_SEQUENCER_OSS) int (*oss_ioctl)(struct snd_emux *emu, int cmd, int p1, int p2); #endif + int (*get_pitch_shift)(struct snd_emux *emu); };
@@ -82,7 +83,6 @@ struct snd_emux { int max_voices; /* Number of voices */ int mem_size; /* memory size (in byte) */ int num_ports; /* number of ports to be created */ - int pitch_shift; /* pitch shift value (for Emu10k1) */ struct snd_emux_operators ops; /* operators */ void *hw; /* hardware */ unsigned long flags; /* other conditions */ diff --git a/sound/pci/emu10k1/emu10k1_callback.c b/sound/pci/emu10k1/emu10k1_callback.c index ad0dea0c2be9..d36234b88fb4 100644 --- a/sound/pci/emu10k1/emu10k1_callback.c +++ b/sound/pci/emu10k1/emu10k1_callback.c @@ -35,6 +35,7 @@ static void terminate_voice(struct snd_emux_voice *vp); static void free_voice(struct snd_emux_voice *vp); static u32 make_fmmod(struct snd_emux_voice *vp); static u32 make_fm2frq2(struct snd_emux_voice *vp); +static int get_pitch_shift(struct snd_emux *emu);
/* * Ensure a value is between two points @@ -58,6 +59,7 @@ static const struct snd_emux_operators emu10k1_ops = { .free_voice = free_voice, .sample_new = snd_emu10k1_sample_new, .sample_free = snd_emu10k1_sample_free, + .get_pitch_shift = get_pitch_shift, };
void @@ -508,3 +510,11 @@ make_fm2frq2(struct snd_emux_voice *vp) LIMITVALUE(pitch, -128, 127); return ((unsigned char)pitch << 8) | freq; } + +static int get_pitch_shift(struct snd_emux *emu) +{ + struct snd_emu10k1 *hw = emu->hw; + + return (hw->card_capabilities->emu_model && + hw->emu1010.word_clock == 44100) ? 0 : -501; +} diff --git a/sound/pci/emu10k1/emu10k1_synth.c b/sound/pci/emu10k1/emu10k1_synth.c index 549013a4a80b..759e66e1105a 100644 --- a/sound/pci/emu10k1/emu10k1_synth.c +++ b/sound/pci/emu10k1/emu10k1_synth.c @@ -43,7 +43,6 @@ static int snd_emu10k1_synth_probe(struct device *_dev) emux->hw = hw; emux->max_voices = arg->max_voices; emux->num_ports = arg->seq_ports; - emux->pitch_shift = -501; emux->memhdr = hw->memhdr; /* maximum two ports */ emux->midi_ports = arg->seq_ports < 2 ? arg->seq_ports : 2; diff --git a/sound/synth/emux/emux_synth.c b/sound/synth/emux/emux_synth.c index a5385efcedb6..075358a533a0 100644 --- a/sound/synth/emux/emux_synth.c +++ b/sound/synth/emux/emux_synth.c @@ -845,7 +845,8 @@ calc_pitch(struct snd_emux_voice *vp)
/* 0xe000: root pitch */ offset += 0xe000 + vp->reg.rate_offset; - offset += vp->emu->pitch_shift; + if (vp->emu->ops.get_pitch_shift) + offset += vp->emu->ops.get_pitch_shift(vp->emu); LIMITVALUE(offset, 0, 0xffff); if (offset == vp->apitch) return 0; /* unchanged */
Some info-querying code still used hw.resolution directly instead of calling snd_timer_hw_resolution(), thus missing a possible hw.c_resolution callback. This patch rectifies that.
Signed-off-by: Oswald Buddenhagen oswald.buddenhagen@gmx.de --- sound/core/timer.c | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-)
diff --git a/sound/core/timer.c b/sound/core/timer.c index e08a37c23add..9d0d2a5c2e15 100644 --- a/sound/core/timer.c +++ b/sound/core/timer.c @@ -1246,6 +1246,7 @@ static void snd_timer_proc_read(struct snd_info_entry *entry, { struct snd_timer *timer; struct snd_timer_instance *ti; + unsigned long resolution;
mutex_lock(®ister_mutex); list_for_each_entry(timer, &snd_timer_list, device_list) { @@ -1269,10 +1270,13 @@ static void snd_timer_proc_read(struct snd_info_entry *entry, timer->tmr_device, timer->tmr_subdevice); } snd_iprintf(buffer, "%s :", timer->name); - if (timer->hw.resolution) + spin_lock_irq(&timer->lock); + resolution = snd_timer_hw_resolution(timer); + spin_unlock_irq(&timer->lock); + if (resolution) snd_iprintf(buffer, " %lu.%03luus (%lu ticks)", - timer->hw.resolution / 1000, - timer->hw.resolution % 1000, + resolution / 1000, + resolution % 1000, timer->hw.ticks); if (timer->hw.flags & SNDRV_TIMER_HW_SLAVE) snd_iprintf(buffer, " SLAVE"); @@ -1662,7 +1666,9 @@ static int snd_timer_user_ginfo(struct file *file, ginfo->flags |= SNDRV_TIMER_FLG_SLAVE; strscpy(ginfo->id, t->id, sizeof(ginfo->id)); strscpy(ginfo->name, t->name, sizeof(ginfo->name)); - ginfo->resolution = t->hw.resolution; + spin_lock_irq(&t->lock); + ginfo->resolution = snd_timer_hw_resolution(t); + spin_unlock_irq(&t->lock); if (t->hw.resolution_min > 0) { ginfo->resolution_min = t->hw.resolution_min; ginfo->resolution_max = t->hw.resolution_max; @@ -1817,7 +1823,9 @@ static int snd_timer_user_info(struct file *file, info->flags |= SNDRV_TIMER_FLG_SLAVE; strscpy(info->id, t->id, sizeof(info->id)); strscpy(info->name, t->name, sizeof(info->name)); - info->resolution = t->hw.resolution; + spin_lock_irq(&t->lock); + info->resolution = snd_timer_hw_resolution(t); + spin_unlock_irq(&t->lock); if (copy_to_user(_info, info, sizeof(*_info))) err = -EFAULT; kfree(info);
The timer was presuming a fixed 48 kHz word clock, like the rest of the code.
Signed-off-by: Oswald Buddenhagen oswald.buddenhagen@gmx.de --- sound/pci/emu10k1/timer.c | 20 ++++++++++++++++++-- 1 file changed, 18 insertions(+), 2 deletions(-)
diff --git a/sound/pci/emu10k1/timer.c b/sound/pci/emu10k1/timer.c index 993663fef885..f3c78adf3248 100644 --- a/sound/pci/emu10k1/timer.c +++ b/sound/pci/emu10k1/timer.c @@ -38,20 +38,36 @@ static int snd_emu10k1_timer_stop(struct snd_timer *timer) return 0; }
+static unsigned long snd_emu10k1_timer_c_resolution(struct snd_timer *timer) +{ + struct snd_emu10k1 *emu = snd_timer_chip(timer); + + if (emu->card_capabilities->emu_model && + emu->emu1010.word_clock == 44100) + return 22676; // 1 sample @ 44.1 kHz = 22.675736...us + else + return 20833; // 1 sample @ 48 kHz = 20.833...us +} + static int snd_emu10k1_timer_precise_resolution(struct snd_timer *timer, unsigned long *num, unsigned long *den) { + struct snd_emu10k1 *emu = snd_timer_chip(timer); + *num = 1; - *den = 48000; + if (emu->card_capabilities->emu_model) + *den = emu->emu1010.word_clock; + else + *den = 48000; return 0; }
static const struct snd_timer_hardware snd_emu10k1_timer_hw = { .flags = SNDRV_TIMER_HW_AUTO, - .resolution = 20833, /* 1 sample @ 48KHZ = 20.833...us */ .ticks = 1024, .start = snd_emu10k1_timer_start, .stop = snd_emu10k1_timer_stop, + .c_resolution = snd_emu10k1_timer_c_resolution, .precise_resolution = snd_emu10k1_timer_precise_resolution, };
Fixes a tentative FIXME. Because we can.
Signed-off-by: Oswald Buddenhagen oswald.buddenhagen@gmx.de --- sound/pci/emu10k1/emupcm.c | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-)
diff --git a/sound/pci/emu10k1/emupcm.c b/sound/pci/emu10k1/emupcm.c index 3ef9130a9577..387288d623d7 100644 --- a/sound/pci/emu10k1/emupcm.c +++ b/sound/pci/emu10k1/emupcm.c @@ -177,12 +177,22 @@ static unsigned int snd_emu10k1_capture_rate_reg(unsigned int rate) } }
+static const unsigned int audigy_capture_rates[9] = { + 8000, 11025, 12000, 16000, 22050, 24000, 32000, 44100, 48000 +}; + +static const struct snd_pcm_hw_constraint_list hw_constraints_audigy_capture_rates = { + .count = 9, + .list = audigy_capture_rates, + .mask = 0 +}; + static unsigned int snd_emu10k1_audigy_capture_rate_reg(unsigned int rate) { switch (rate) { case 8000: return A_ADCCR_SAMPLERATE_8; case 11025: return A_ADCCR_SAMPLERATE_11; - case 12000: return A_ADCCR_SAMPLERATE_12; /* really supported? */ + case 12000: return A_ADCCR_SAMPLERATE_12; case 16000: return ADCCR_SAMPLERATE_16; case 22050: return ADCCR_SAMPLERATE_22; case 24000: return ADCCR_SAMPLERATE_24; @@ -209,7 +219,8 @@ static void snd_emu10k1_constrain_capture_rates(struct snd_emu10k1 *emu, return; } snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_RATE, - &hw_constraints_capture_rates); + emu->audigy ? &hw_constraints_audigy_capture_rates : + &hw_constraints_capture_rates); }
static void snd_emu1010_constrain_efx_rate(struct snd_emu10k1 *emu,
The file is called spdif-in, but we abused it to show only sample rates from various sources. Rectify it as far as possible (the FPGA doesn't give us a lot of information).
Signed-off-by: Oswald Buddenhagen oswald.buddenhagen@gmx.de
---
FIXME: the polarity of "no copy" isn't clear - it could mean either "no copyright asserted" or "no copies permitted". my attempts to test it with an 0404b fed by an intel hda board went nowhere - the bit is never set regardless of what i poke into the hda codec, and i don't know whether the source or the card is to blame. --- sound/pci/emu10k1/emuproc.c | 8 ++++++++ 1 file changed, 8 insertions(+)
diff --git a/sound/pci/emu10k1/emuproc.c b/sound/pci/emu10k1/emuproc.c index 993b35362499..7e2cc532471f 100644 --- a/sound/pci/emu10k1/emuproc.c +++ b/sound/pci/emu10k1/emuproc.c @@ -194,6 +194,14 @@ static void snd_emu10k1_proc_spdif_read(struct snd_info_entry *entry, emu->card_capabilities->emu_model == EMU_MODEL_EMU1010) snd_iprintf(buffer, "BNC rate: %dHz\n", snd_emu1010_get_raw_rate(emu, EMU_HANA_WCLOCK_SYNC_BNC)); + + snd_emu1010_fpga_read(emu, EMU_HANA_SPDIF_MODE, &value); + if (value & EMU_HANA_SPDIF_MODE_RX_INVALID) + snd_iprintf(buffer, "\nS/PDIF input invalid\n"); + else + snd_iprintf(buffer, "\nS/PDIF mode: %s%s\n", + value & EMU_HANA_SPDIF_MODE_RX_PRO ? "professional" : "consumer", + value & EMU_HANA_SPDIF_MODE_RX_NOCOPY ? ", no copy" : ""); } else { snd_emu10k1_proc_spdif_status(emu, buffer, "CD-ROM S/PDIF In", CDCS, CDSRCS); snd_emu10k1_proc_spdif_status(emu, buffer, "Optical or Coax S/PDIF In", GPSCS, GPSRCS);
On Mon, 12 Jun 2023 21:13:16 +0200, Oswald Buddenhagen wrote:
Oswald Buddenhagen (9): ALSA: emu10k1: split off E-MU fallback clock from clock source ALSA: emu10k1: make available E-MU clock sources card-specific ALSA: emu10k1: query rate of external clock sources on E-MU cards ALSA: emu10k1: fix sample rates for E-MU cards at 44.1 kHz word clock ALSA: emu10k1: fix synthesizer pitch for E-MU cards at 44.1 kHz ALSA: timer: minimize open-coded access to hw.resolution ALSA: emu10k1: fix timer for E-MU cards at 44.1 kHz word clock ALSA: emu10k1: add support for 12 kHz capture on Audigy ALSA: emu10k1: actually show some S/PDIF status in /proc for E-MU cards
Applied all patches now. Thanks.
Takashi
participants (2)
-
Oswald Buddenhagen
-
Takashi Iwai