#include <linux/delay.h>
#include <linux/pci.h>
#include <linux/pm.h>
#include <linux/init.h>
#include <linux/interrupt.h>
#include <linux/slab.h>
#include <linux/gameport.h>
#include <linux/mutex.h>
#include <linux/export.h>
#include <linux/module.h>
#include <linux/firmware.h>
#include <linux/vmalloc.h>
#include <linux/io.h>
#include <sound/core.h>
#include <sound/control.h>
#include <sound/info.h>
#include <sound/pcm.h>
#include <sound/pcm_params.h>
#include "cs46xx.h"
#include "cs46xx_lib.h"
#include "dsp_spos.h"
static void amp_voyetra(struct snd_cs46xx *chip, int change);
#ifdef CONFIG_SND_CS46XX_NEW_DSP
static const struct snd_pcm_ops snd_cs46xx_playback_rear_ops;
static const struct snd_pcm_ops snd_cs46xx_playback_indirect_rear_ops;
static const struct snd_pcm_ops snd_cs46xx_playback_clfe_ops;
static const struct snd_pcm_ops snd_cs46xx_playback_indirect_clfe_ops;
static const struct snd_pcm_ops snd_cs46xx_playback_iec958_ops;
static const struct snd_pcm_ops snd_cs46xx_playback_indirect_iec958_ops;
#endif
static const struct snd_pcm_ops snd_cs46xx_playback_ops;
static const struct snd_pcm_ops snd_cs46xx_playback_indirect_ops;
static const struct snd_pcm_ops snd_cs46xx_capture_ops;
static const struct snd_pcm_ops snd_cs46xx_capture_indirect_ops;
static unsigned short snd_cs46xx_codec_read(struct snd_cs46xx *chip,
unsigned short reg,
int codec_index)
{ … }
static unsigned short snd_cs46xx_ac97_read(struct snd_ac97 * ac97,
unsigned short reg)
{ … }
static void snd_cs46xx_codec_write(struct snd_cs46xx *chip,
unsigned short reg,
unsigned short val,
int codec_index)
{ … }
static void snd_cs46xx_ac97_write(struct snd_ac97 *ac97,
unsigned short reg,
unsigned short val)
{ … }
int snd_cs46xx_download(struct snd_cs46xx *chip,
u32 *src,
unsigned long offset,
unsigned long len)
{ … }
static inline void memcpy_le32(void *dst, const void *src, unsigned int len)
{ … }
#ifdef CONFIG_SND_CS46XX_NEW_DSP
static const char *module_names[CS46XX_DSP_MODULES] = …;
MODULE_FIRMWARE(…) …;
MODULE_FIRMWARE(…) …;
MODULE_FIRMWARE(…) …;
MODULE_FIRMWARE(…) …;
MODULE_FIRMWARE(…) …;
static void free_module_desc(struct dsp_module_desc *module)
{ … }
static int load_firmware(struct snd_cs46xx *chip,
struct dsp_module_desc **module_ret,
const char *fw_name)
{ … }
int snd_cs46xx_clear_BA1(struct snd_cs46xx *chip,
unsigned long offset,
unsigned long len)
{ … }
#else
struct ba1_struct {
struct {
u32 offset;
u32 size;
} memory[BA1_MEMORY_COUNT];
u32 map[BA1_DWORD_SIZE];
};
MODULE_FIRMWARE("cs46xx/ba1");
static int load_firmware(struct snd_cs46xx *chip)
{
const struct firmware *fw;
int i, size, err;
err = request_firmware(&fw, "cs46xx/ba1", &chip->pci->dev);
if (err < 0)
return err;
if (fw->size != sizeof(*chip->ba1)) {
err = -EINVAL;
goto error;
}
chip->ba1 = vmalloc(sizeof(*chip->ba1));
if (!chip->ba1) {
err = -ENOMEM;
goto error;
}
memcpy_le32(chip->ba1, fw->data, sizeof(*chip->ba1));
size = 0;
for (i = 0; i < BA1_MEMORY_COUNT; i++)
size += chip->ba1->memory[i].size;
if (size > BA1_DWORD_SIZE * 4)
err = -EINVAL;
error:
release_firmware(fw);
return err;
}
static __maybe_unused int snd_cs46xx_download_image(struct snd_cs46xx *chip)
{
int idx, err;
unsigned int offset = 0;
struct ba1_struct *ba1 = chip->ba1;
for (idx = 0; idx < BA1_MEMORY_COUNT; idx++) {
err = snd_cs46xx_download(chip,
&ba1->map[offset],
ba1->memory[idx].offset,
ba1->memory[idx].size);
if (err < 0)
return err;
offset += ba1->memory[idx].size >> 2;
}
return 0;
}
#endif
static void snd_cs46xx_reset(struct snd_cs46xx *chip)
{ … }
static int cs46xx_wait_for_fifo(struct snd_cs46xx * chip,int retry_timeout)
{ … }
static void snd_cs46xx_clear_serial_FIFOs(struct snd_cs46xx *chip)
{ … }
static void snd_cs46xx_proc_start(struct snd_cs46xx *chip)
{ … }
static void snd_cs46xx_proc_stop(struct snd_cs46xx *chip)
{ … }
#define GOF_PER_SEC …
static void snd_cs46xx_set_play_sample_rate(struct snd_cs46xx *chip, unsigned int rate)
{ … }
static void snd_cs46xx_set_capture_sample_rate(struct snd_cs46xx *chip, unsigned int rate)
{ … }
static void snd_cs46xx_pb_trans_copy(struct snd_pcm_substream *substream,
struct snd_pcm_indirect *rec, size_t bytes)
{ … }
static int snd_cs46xx_playback_transfer(struct snd_pcm_substream *substream)
{ … }
static void snd_cs46xx_cp_trans_copy(struct snd_pcm_substream *substream,
struct snd_pcm_indirect *rec, size_t bytes)
{ … }
static int snd_cs46xx_capture_transfer(struct snd_pcm_substream *substream)
{ … }
static snd_pcm_uframes_t snd_cs46xx_playback_direct_pointer(struct snd_pcm_substream *substream)
{ … }
static snd_pcm_uframes_t snd_cs46xx_playback_indirect_pointer(struct snd_pcm_substream *substream)
{ … }
static snd_pcm_uframes_t snd_cs46xx_capture_direct_pointer(struct snd_pcm_substream *substream)
{ … }
static snd_pcm_uframes_t snd_cs46xx_capture_indirect_pointer(struct snd_pcm_substream *substream)
{ … }
static int snd_cs46xx_playback_trigger(struct snd_pcm_substream *substream,
int cmd)
{ … }
static int snd_cs46xx_capture_trigger(struct snd_pcm_substream *substream,
int cmd)
{ … }
#ifdef CONFIG_SND_CS46XX_NEW_DSP
static int _cs46xx_adjust_sample_rate (struct snd_cs46xx *chip, struct snd_cs46xx_pcm *cpcm,
int sample_rate)
{ … }
#endif
static int snd_cs46xx_playback_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *hw_params)
{ … }
static int snd_cs46xx_playback_hw_free(struct snd_pcm_substream *substream)
{ … }
static int snd_cs46xx_playback_prepare(struct snd_pcm_substream *substream)
{ … }
static int snd_cs46xx_capture_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *hw_params)
{ … }
static int snd_cs46xx_capture_hw_free(struct snd_pcm_substream *substream)
{ … }
static int snd_cs46xx_capture_prepare(struct snd_pcm_substream *substream)
{ … }
static irqreturn_t snd_cs46xx_interrupt(int irq, void *dev_id)
{ … }
static const struct snd_pcm_hardware snd_cs46xx_playback = …;
static const struct snd_pcm_hardware snd_cs46xx_capture = …;
#ifdef CONFIG_SND_CS46XX_NEW_DSP
static const unsigned int period_sizes[] = …;
static const struct snd_pcm_hw_constraint_list hw_constraints_period_sizes = …;
#endif
static void snd_cs46xx_pcm_free_substream(struct snd_pcm_runtime *runtime)
{ … }
static int _cs46xx_playback_open_channel (struct snd_pcm_substream *substream,int pcm_channel_id)
{ … }
static int snd_cs46xx_playback_open(struct snd_pcm_substream *substream)
{ … }
#ifdef CONFIG_SND_CS46XX_NEW_DSP
static int snd_cs46xx_playback_open_rear(struct snd_pcm_substream *substream)
{ … }
static int snd_cs46xx_playback_open_clfe(struct snd_pcm_substream *substream)
{ … }
static int snd_cs46xx_playback_open_iec958(struct snd_pcm_substream *substream)
{ … }
static int snd_cs46xx_playback_close(struct snd_pcm_substream *substream);
static int snd_cs46xx_playback_close_iec958(struct snd_pcm_substream *substream)
{ … }
#endif
static int snd_cs46xx_capture_open(struct snd_pcm_substream *substream)
{ … }
static int snd_cs46xx_playback_close(struct snd_pcm_substream *substream)
{ … }
static int snd_cs46xx_capture_close(struct snd_pcm_substream *substream)
{ … }
#ifdef CONFIG_SND_CS46XX_NEW_DSP
static const struct snd_pcm_ops snd_cs46xx_playback_rear_ops = …;
static const struct snd_pcm_ops snd_cs46xx_playback_indirect_rear_ops = …;
static const struct snd_pcm_ops snd_cs46xx_playback_clfe_ops = …;
static const struct snd_pcm_ops snd_cs46xx_playback_indirect_clfe_ops = …;
static const struct snd_pcm_ops snd_cs46xx_playback_iec958_ops = …;
static const struct snd_pcm_ops snd_cs46xx_playback_indirect_iec958_ops = …;
#endif
static const struct snd_pcm_ops snd_cs46xx_playback_ops = …;
static const struct snd_pcm_ops snd_cs46xx_playback_indirect_ops = …;
static const struct snd_pcm_ops snd_cs46xx_capture_ops = …;
static const struct snd_pcm_ops snd_cs46xx_capture_indirect_ops = …;
#ifdef CONFIG_SND_CS46XX_NEW_DSP
#define MAX_PLAYBACK_CHANNELS …
#else
#define MAX_PLAYBACK_CHANNELS …
#endif
int snd_cs46xx_pcm(struct snd_cs46xx *chip, int device)
{ … }
#ifdef CONFIG_SND_CS46XX_NEW_DSP
int snd_cs46xx_pcm_rear(struct snd_cs46xx *chip, int device)
{ … }
int snd_cs46xx_pcm_center_lfe(struct snd_cs46xx *chip, int device)
{ … }
int snd_cs46xx_pcm_iec958(struct snd_cs46xx *chip, int device)
{ … }
#endif
static void snd_cs46xx_mixer_free_ac97(struct snd_ac97 *ac97)
{ … }
static int snd_cs46xx_vol_info(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_info *uinfo)
{ … }
static int snd_cs46xx_vol_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
{ … }
static int snd_cs46xx_vol_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
{ … }
#ifdef CONFIG_SND_CS46XX_NEW_DSP
static int snd_cs46xx_vol_dac_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
{ … }
static int snd_cs46xx_vol_dac_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
{ … }
#if 0
static int snd_cs46xx_vol_iec958_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
{
struct snd_cs46xx *chip = snd_kcontrol_chip(kcontrol);
ucontrol->value.integer.value[0] = chip->dsp_spos_instance->spdif_input_volume_left;
ucontrol->value.integer.value[1] = chip->dsp_spos_instance->spdif_input_volume_right;
return 0;
}
static int snd_cs46xx_vol_iec958_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
{
struct snd_cs46xx *chip = snd_kcontrol_chip(kcontrol);
int change = 0;
if (chip->dsp_spos_instance->spdif_input_volume_left != ucontrol->value.integer.value[0] ||
chip->dsp_spos_instance->spdif_input_volume_right!= ucontrol->value.integer.value[1]) {
cs46xx_dsp_set_iec958_volume (chip,
ucontrol->value.integer.value[0],
ucontrol->value.integer.value[1]);
change = 1;
}
return change;
}
#endif
#define snd_mixer_boolean_info …
static int snd_cs46xx_iec958_get(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{ … }
static int snd_cs46xx_iec958_put(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{ … }
static int snd_cs46xx_adc_capture_get(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{ … }
static int snd_cs46xx_adc_capture_put(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{ … }
static int snd_cs46xx_pcm_capture_get(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{ … }
static int snd_cs46xx_pcm_capture_put(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{ … }
static int snd_herc_spdif_select_get(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{ … }
static int snd_herc_spdif_select_put(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{ … }
static int snd_cs46xx_spdif_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
{ … }
static int snd_cs46xx_spdif_default_get(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{ … }
static int snd_cs46xx_spdif_default_put(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{ … }
static int snd_cs46xx_spdif_mask_get(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{ … }
static int snd_cs46xx_spdif_stream_get(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{ … }
static int snd_cs46xx_spdif_stream_put(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{ … }
#endif
static const struct snd_kcontrol_new snd_cs46xx_controls[] = …;
#ifdef CONFIG_SND_CS46XX_NEW_DSP
static int snd_cs46xx_front_dup_get(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{ … }
static int snd_cs46xx_front_dup_put(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{ … }
static const struct snd_kcontrol_new snd_cs46xx_front_dup_ctl = …;
#endif
#ifdef CONFIG_SND_CS46XX_NEW_DSP
static const struct snd_kcontrol_new snd_hercules_controls[] = …;
static void snd_cs46xx_codec_reset (struct snd_ac97 * ac97)
{ … }
#endif
static int cs46xx_detect_codec(struct snd_cs46xx *chip, int codec)
{ … }
int snd_cs46xx_mixer(struct snd_cs46xx *chip, int spdif_device)
{ … }
static void snd_cs46xx_midi_reset(struct snd_cs46xx *chip)
{ … }
static int snd_cs46xx_midi_input_open(struct snd_rawmidi_substream *substream)
{ … }
static int snd_cs46xx_midi_input_close(struct snd_rawmidi_substream *substream)
{ … }
static int snd_cs46xx_midi_output_open(struct snd_rawmidi_substream *substream)
{ … }
static int snd_cs46xx_midi_output_close(struct snd_rawmidi_substream *substream)
{ … }
static void snd_cs46xx_midi_input_trigger(struct snd_rawmidi_substream *substream, int up)
{ … }
static void snd_cs46xx_midi_output_trigger(struct snd_rawmidi_substream *substream, int up)
{ … }
static const struct snd_rawmidi_ops snd_cs46xx_midi_output = …;
static const struct snd_rawmidi_ops snd_cs46xx_midi_input = …;
int snd_cs46xx_midi(struct snd_cs46xx *chip, int device)
{ … }
#if IS_REACHABLE(CONFIG_GAMEPORT)
static void snd_cs46xx_gameport_trigger(struct gameport *gameport)
{ … }
static unsigned char snd_cs46xx_gameport_read(struct gameport *gameport)
{ … }
static int snd_cs46xx_gameport_cooked_read(struct gameport *gameport, int *axes, int *buttons)
{ … }
static int snd_cs46xx_gameport_open(struct gameport *gameport, int mode)
{ … }
int snd_cs46xx_gameport(struct snd_cs46xx *chip)
{ … }
static inline void snd_cs46xx_remove_gameport(struct snd_cs46xx *chip)
{ … }
#else
int snd_cs46xx_gameport(struct snd_cs46xx *chip) { return -ENOSYS; }
static inline void snd_cs46xx_remove_gameport(struct snd_cs46xx *chip) { }
#endif
#ifdef CONFIG_SND_PROC_FS
static ssize_t snd_cs46xx_io_read(struct snd_info_entry *entry,
void *file_private_data,
struct file *file, char __user *buf,
size_t count, loff_t pos)
{ … }
static const struct snd_info_entry_ops snd_cs46xx_proc_io_ops = …;
static int snd_cs46xx_proc_init(struct snd_card *card, struct snd_cs46xx *chip)
{ … }
static int snd_cs46xx_proc_done(struct snd_cs46xx *chip)
{ … }
#else
#define snd_cs46xx_proc_init …
#define snd_cs46xx_proc_done …
#endif
static void snd_cs46xx_hw_stop(struct snd_cs46xx *chip)
{ … }
static void snd_cs46xx_free(struct snd_card *card)
{ … }
static int snd_cs46xx_chip_init(struct snd_cs46xx *chip)
{ … }
static void cs46xx_enable_stream_irqs(struct snd_cs46xx *chip)
{ … }
int snd_cs46xx_start_dsp(struct snd_cs46xx *chip)
{ … }
static void amp_none(struct snd_cs46xx *chip, int change)
{ … }
#ifdef CONFIG_SND_CS46XX_NEW_DSP
static int voyetra_setup_eapd_slot(struct snd_cs46xx *chip)
{ … }
#endif
static void amp_voyetra(struct snd_cs46xx *chip, int change)
{ … }
static void hercules_init(struct snd_cs46xx *chip)
{ … }
static void amp_hercules(struct snd_cs46xx *chip, int change)
{ … }
static void voyetra_mixer_init (struct snd_cs46xx *chip)
{ … }
static void hercules_mixer_init (struct snd_cs46xx *chip)
{ … }
#if 0
static void amp_voyetra_4294(struct snd_cs46xx *chip, int change)
{
chip->amplifier += change;
if (chip->amplifier) {
snd_cs46xx_codec_write(chip, 0x4C,
snd_cs46xx_codec_read(chip, 0x4C) & 0xFE7F);
snd_cs46xx_codec_write(chip, 0x4E,
snd_cs46xx_codec_read(chip, 0x4E) | 0x0180);
snd_cs46xx_codec_write(chip, 0x54,
snd_cs46xx_codec_read(chip, 0x54) & ~0x0180);
} else {
snd_cs46xx_codec_write(chip, 0x54,
snd_cs46xx_codec_read(chip, 0x54) | 0x0180);
}
}
#endif
static void clkrun_hack(struct snd_cs46xx *chip, int change)
{ … }
static void clkrun_init(struct snd_cs46xx *chip)
{ … }
struct cs_card_type
{ … };
static struct cs_card_type cards[] = …;
#ifdef CONFIG_PM_SLEEP
static const unsigned int saved_regs[] = …;
static int snd_cs46xx_suspend(struct device *dev)
{ … }
static int snd_cs46xx_resume(struct device *dev)
{ … }
SIMPLE_DEV_PM_OPS(snd_cs46xx_pm, snd_cs46xx_suspend, snd_cs46xx_resume);
#endif
int snd_cs46xx_create(struct snd_card *card,
struct pci_dev *pci,
int external_amp, int thinkpad)
{ … }