linux/sound/pci/sonicvibes.c

// SPDX-License-Identifier: GPL-2.0-or-later
/*
 *  Driver for S3 SonicVibes soundcard
 *  Copyright (c) by Jaroslav Kysela <[email protected]>
 *
 *  BUGS:
 *    It looks like 86c617 rev 3 doesn't supports DDMA buffers above 16MB?
 *    Driver sometimes hangs... Nobody knows why at this moment...
 */

#include <linux/delay.h>
#include <linux/init.h>
#include <linux/interrupt.h>
#include <linux/pci.h>
#include <linux/slab.h>
#include <linux/gameport.h>
#include <linux/module.h>
#include <linux/dma-mapping.h>
#include <linux/io.h>

#include <sound/core.h>
#include <sound/pcm.h>
#include <sound/info.h>
#include <sound/control.h>
#include <sound/mpu401.h>
#include <sound/opl3.h>
#include <sound/initval.h>

MODULE_AUTHOR();
MODULE_DESCRIPTION();
MODULE_LICENSE();

#if IS_REACHABLE(CONFIG_GAMEPORT)
#define SUPPORT_JOYSTICK
#endif

static int index[SNDRV_CARDS] =;	/* Index 0-MAX */
static char *id[SNDRV_CARDS] =;	/* ID for this card */
static bool enable[SNDRV_CARDS] =;	/* Enable this card */
static bool reverb[SNDRV_CARDS];
static bool mge[SNDRV_CARDS];
static unsigned int dmaio =;	/* DDMA i/o address */

module_param_array();
MODULE_PARM_DESC();
module_param_array();
MODULE_PARM_DESC();
module_param_array();
MODULE_PARM_DESC();
module_param_array();
MODULE_PARM_DESC();
module_param_array();
MODULE_PARM_DESC();
module_param_hw(dmaio, uint, ioport, 0444);
MODULE_PARM_DESC();

/*
 * Enhanced port direct registers
 */

#define SV_REG(sonic, x)

#define SV_REG_CONTROL
#define SV_ENHANCED
#define SV_TEST
#define SV_REVERB
#define SV_WAVETABLE
#define SV_INTA
#define SV_RESET
#define SV_REG_IRQMASK
#define SV_DMAA_MASK
#define SV_DMAC_MASK
#define SV_SPEC_MASK
#define SV_UD_MASK
#define SV_MIDI_MASK
#define SV_REG_STATUS
#define SV_DMAA_IRQ
#define SV_DMAC_IRQ
#define SV_SPEC_IRQ
#define SV_UD_IRQ
#define SV_MIDI_IRQ
#define SV_REG_INDEX
#define SV_MCE
#define SV_TRD
#define SV_REG_DATA

/*
 * Enhanced port indirect registers
 */

#define SV_IREG_LEFT_ADC
#define SV_IREG_RIGHT_ADC
#define SV_IREG_LEFT_AUX1
#define SV_IREG_RIGHT_AUX1
#define SV_IREG_LEFT_CD
#define SV_IREG_RIGHT_CD
#define SV_IREG_LEFT_LINE
#define SV_IREG_RIGHT_LINE
#define SV_IREG_MIC
#define SV_IREG_GAME_PORT
#define SV_IREG_LEFT_SYNTH
#define SV_IREG_RIGHT_SYNTH
#define SV_IREG_LEFT_AUX2
#define SV_IREG_RIGHT_AUX2
#define SV_IREG_LEFT_ANALOG
#define SV_IREG_RIGHT_ANALOG
#define SV_IREG_LEFT_PCM
#define SV_IREG_RIGHT_PCM
#define SV_IREG_DMA_DATA_FMT
#define SV_IREG_PC_ENABLE
#define SV_IREG_UD_BUTTON
#define SV_IREG_REVISION
#define SV_IREG_ADC_OUTPUT_CTRL
#define SV_IREG_DMA_A_UPPER
#define SV_IREG_DMA_A_LOWER
#define SV_IREG_DMA_C_UPPER
#define SV_IREG_DMA_C_LOWER
#define SV_IREG_PCM_RATE_LOW
#define SV_IREG_PCM_RATE_HIGH
#define SV_IREG_SYNTH_RATE_LOW
#define SV_IREG_SYNTH_RATE_HIGH
#define SV_IREG_ADC_CLOCK
#define SV_IREG_ADC_ALT_RATE
#define SV_IREG_ADC_PLL_M
#define SV_IREG_ADC_PLL_N
#define SV_IREG_SYNTH_PLL_M
#define SV_IREG_SYNTH_PLL_N
#define SV_IREG_MPU401
#define SV_IREG_DRIVE_CTRL
#define SV_IREG_SRS_SPACE
#define SV_IREG_SRS_CENTER
#define SV_IREG_WAVE_SOURCE
#define SV_IREG_ANALOG_POWER
#define SV_IREG_DIGITAL_POWER

#define SV_IREG_ADC_PLL
#define SV_IREG_SYNTH_PLL

/*
 *  DMA registers
 */

#define SV_DMA_ADDR0
#define SV_DMA_ADDR1
#define SV_DMA_ADDR2
#define SV_DMA_ADDR3
#define SV_DMA_COUNT0
#define SV_DMA_COUNT1
#define SV_DMA_COUNT2
#define SV_DMA_MODE
#define SV_DMA_RESET
#define SV_DMA_MASK

/*
 *  Record sources
 */

#define SV_RECSRC_RESERVED
#define SV_RECSRC_CD
#define SV_RECSRC_DAC
#define SV_RECSRC_AUX2
#define SV_RECSRC_LINE
#define SV_RECSRC_AUX1
#define SV_RECSRC_MIC
#define SV_RECSRC_OUT

/*
 *  constants
 */

#define SV_FULLRATE
#define SV_REFFREQUENCY
#define SV_ADCMULT

#define SV_MODE_PLAY
#define SV_MODE_CAPTURE

/*

 */

struct sonicvibes {};

static const struct pci_device_id snd_sonic_ids[] =;

MODULE_DEVICE_TABLE(pci, snd_sonic_ids);

static const struct snd_ratden sonicvibes_adc_clock =;
static const struct snd_pcm_hw_constraint_ratdens snd_sonicvibes_hw_constraints_adc_clock =;

/*
 *  common I/O routines
 */

static inline void snd_sonicvibes_setdmaa(struct sonicvibes * sonic,
					  unsigned int addr,
					  unsigned int count)
{}

static inline void snd_sonicvibes_setdmac(struct sonicvibes * sonic,
					  unsigned int addr,
					  unsigned int count)
{}

static inline unsigned int snd_sonicvibes_getdmaa(struct sonicvibes * sonic)
{}

static inline unsigned int snd_sonicvibes_getdmac(struct sonicvibes * sonic)
{}

static void snd_sonicvibes_out1(struct sonicvibes * sonic,
				unsigned char reg,
				unsigned char value)
{}

static void snd_sonicvibes_out(struct sonicvibes * sonic,
			       unsigned char reg,
			       unsigned char value)
{}

static unsigned char snd_sonicvibes_in1(struct sonicvibes * sonic, unsigned char reg)
{}

static unsigned char snd_sonicvibes_in(struct sonicvibes * sonic, unsigned char reg)
{}

#if 0
static void snd_sonicvibes_debug(struct sonicvibes * sonic)
{
	dev_dbg(sonic->card->dev,
		"SV REGS:          INDEX = 0x%02x                   STATUS = 0x%02x\n",
		inb(SV_REG(sonic, INDEX)), inb(SV_REG(sonic, STATUS)));
	dev_dbg(sonic->card->dev,
		"  0x00: left input      = 0x%02x    0x20: synth rate low  = 0x%02x\n",
		snd_sonicvibes_in(sonic, 0x00), snd_sonicvibes_in(sonic, 0x20));
	dev_dbg(sonic->card->dev,
		"  0x01: right input     = 0x%02x    0x21: synth rate high = 0x%02x\n",
		snd_sonicvibes_in(sonic, 0x01), snd_sonicvibes_in(sonic, 0x21));
	dev_dbg(sonic->card->dev,
		"  0x02: left AUX1       = 0x%02x    0x22: ADC clock       = 0x%02x\n",
		snd_sonicvibes_in(sonic, 0x02), snd_sonicvibes_in(sonic, 0x22));
	dev_dbg(sonic->card->dev,
		"  0x03: right AUX1      = 0x%02x    0x23: ADC alt rate    = 0x%02x\n",
		snd_sonicvibes_in(sonic, 0x03), snd_sonicvibes_in(sonic, 0x23));
	dev_dbg(sonic->card->dev,
		"  0x04: left CD         = 0x%02x    0x24: ADC pll M       = 0x%02x\n",
		snd_sonicvibes_in(sonic, 0x04), snd_sonicvibes_in(sonic, 0x24));
	dev_dbg(sonic->card->dev,
		"  0x05: right CD        = 0x%02x    0x25: ADC pll N       = 0x%02x\n",
		snd_sonicvibes_in(sonic, 0x05), snd_sonicvibes_in(sonic, 0x25));
	dev_dbg(sonic->card->dev,
		"  0x06: left line       = 0x%02x    0x26: Synth pll M     = 0x%02x\n",
		snd_sonicvibes_in(sonic, 0x06), snd_sonicvibes_in(sonic, 0x26));
	dev_dbg(sonic->card->dev,
		"  0x07: right line      = 0x%02x    0x27: Synth pll N     = 0x%02x\n",
		snd_sonicvibes_in(sonic, 0x07), snd_sonicvibes_in(sonic, 0x27));
	dev_dbg(sonic->card->dev,
		"  0x08: MIC             = 0x%02x    0x28: ---             = 0x%02x\n",
		snd_sonicvibes_in(sonic, 0x08), snd_sonicvibes_in(sonic, 0x28));
	dev_dbg(sonic->card->dev,
		"  0x09: Game port       = 0x%02x    0x29: ---             = 0x%02x\n",
		snd_sonicvibes_in(sonic, 0x09), snd_sonicvibes_in(sonic, 0x29));
	dev_dbg(sonic->card->dev,
		"  0x0a: left synth      = 0x%02x    0x2a: MPU401          = 0x%02x\n",
		snd_sonicvibes_in(sonic, 0x0a), snd_sonicvibes_in(sonic, 0x2a));
	dev_dbg(sonic->card->dev,
		"  0x0b: right synth     = 0x%02x    0x2b: drive ctrl      = 0x%02x\n",
		snd_sonicvibes_in(sonic, 0x0b), snd_sonicvibes_in(sonic, 0x2b));
	dev_dbg(sonic->card->dev,
		"  0x0c: left AUX2       = 0x%02x    0x2c: SRS space       = 0x%02x\n",
		snd_sonicvibes_in(sonic, 0x0c), snd_sonicvibes_in(sonic, 0x2c));
	dev_dbg(sonic->card->dev,
		"  0x0d: right AUX2      = 0x%02x    0x2d: SRS center      = 0x%02x\n",
		snd_sonicvibes_in(sonic, 0x0d), snd_sonicvibes_in(sonic, 0x2d));
	dev_dbg(sonic->card->dev,
		"  0x0e: left analog     = 0x%02x    0x2e: wave source     = 0x%02x\n",
		snd_sonicvibes_in(sonic, 0x0e), snd_sonicvibes_in(sonic, 0x2e));
	dev_dbg(sonic->card->dev,
		"  0x0f: right analog    = 0x%02x    0x2f: ---             = 0x%02x\n",
		snd_sonicvibes_in(sonic, 0x0f), snd_sonicvibes_in(sonic, 0x2f));
	dev_dbg(sonic->card->dev,
		"  0x10: left PCM        = 0x%02x    0x30: analog power    = 0x%02x\n",
		snd_sonicvibes_in(sonic, 0x10), snd_sonicvibes_in(sonic, 0x30));
	dev_dbg(sonic->card->dev,
		"  0x11: right PCM       = 0x%02x    0x31: analog power    = 0x%02x\n",
		snd_sonicvibes_in(sonic, 0x11), snd_sonicvibes_in(sonic, 0x31));
	dev_dbg(sonic->card->dev,
		"  0x12: DMA data format = 0x%02x    0x32: ---             = 0x%02x\n",
		snd_sonicvibes_in(sonic, 0x12), snd_sonicvibes_in(sonic, 0x32));
	dev_dbg(sonic->card->dev,
		"  0x13: P/C enable      = 0x%02x    0x33: ---             = 0x%02x\n",
		snd_sonicvibes_in(sonic, 0x13), snd_sonicvibes_in(sonic, 0x33));
	dev_dbg(sonic->card->dev,
		"  0x14: U/D button      = 0x%02x    0x34: ---             = 0x%02x\n",
		snd_sonicvibes_in(sonic, 0x14), snd_sonicvibes_in(sonic, 0x34));
	dev_dbg(sonic->card->dev,
		"  0x15: revision        = 0x%02x    0x35: ---             = 0x%02x\n",
		snd_sonicvibes_in(sonic, 0x15), snd_sonicvibes_in(sonic, 0x35));
	dev_dbg(sonic->card->dev,
		"  0x16: ADC output ctrl = 0x%02x    0x36: ---             = 0x%02x\n",
		snd_sonicvibes_in(sonic, 0x16), snd_sonicvibes_in(sonic, 0x36));
	dev_dbg(sonic->card->dev,
		"  0x17: ---             = 0x%02x    0x37: ---             = 0x%02x\n",
		snd_sonicvibes_in(sonic, 0x17), snd_sonicvibes_in(sonic, 0x37));
	dev_dbg(sonic->card->dev,
		"  0x18: DMA A upper cnt = 0x%02x    0x38: ---             = 0x%02x\n",
		snd_sonicvibes_in(sonic, 0x18), snd_sonicvibes_in(sonic, 0x38));
	dev_dbg(sonic->card->dev,
		"  0x19: DMA A lower cnt = 0x%02x    0x39: ---             = 0x%02x\n",
		snd_sonicvibes_in(sonic, 0x19), snd_sonicvibes_in(sonic, 0x39));
	dev_dbg(sonic->card->dev,
		"  0x1a: ---             = 0x%02x    0x3a: ---             = 0x%02x\n",
		snd_sonicvibes_in(sonic, 0x1a), snd_sonicvibes_in(sonic, 0x3a));
	dev_dbg(sonic->card->dev,
		"  0x1b: ---             = 0x%02x    0x3b: ---             = 0x%02x\n",
		snd_sonicvibes_in(sonic, 0x1b), snd_sonicvibes_in(sonic, 0x3b));
	dev_dbg(sonic->card->dev,
		"  0x1c: DMA C upper cnt = 0x%02x    0x3c: ---             = 0x%02x\n",
		snd_sonicvibes_in(sonic, 0x1c), snd_sonicvibes_in(sonic, 0x3c));
	dev_dbg(sonic->card->dev,
		"  0x1d: DMA C upper cnt = 0x%02x    0x3d: ---             = 0x%02x\n",
		snd_sonicvibes_in(sonic, 0x1d), snd_sonicvibes_in(sonic, 0x3d));
	dev_dbg(sonic->card->dev,
		"  0x1e: PCM rate low    = 0x%02x    0x3e: ---             = 0x%02x\n",
		snd_sonicvibes_in(sonic, 0x1e), snd_sonicvibes_in(sonic, 0x3e));
	dev_dbg(sonic->card->dev,
		"  0x1f: PCM rate high   = 0x%02x    0x3f: ---             = 0x%02x\n",
		snd_sonicvibes_in(sonic, 0x1f), snd_sonicvibes_in(sonic, 0x3f));
}

#endif

static void snd_sonicvibes_setfmt(struct sonicvibes * sonic,
                                  unsigned char mask,
                                  unsigned char value)
{}

static void snd_sonicvibes_pll(unsigned int rate,
			       unsigned int *res_r,
			       unsigned int *res_m,
			       unsigned int *res_n)
{}

static void snd_sonicvibes_setpll(struct sonicvibes * sonic,
                                  unsigned char reg,
                                  unsigned int rate)
{}

static void snd_sonicvibes_set_adc_rate(struct sonicvibes * sonic, unsigned int rate)
{}

static int snd_sonicvibes_hw_constraint_dac_rate(struct snd_pcm_hw_params *params,
						 struct snd_pcm_hw_rule *rule)
{}

static void snd_sonicvibes_set_dac_rate(struct sonicvibes * sonic, unsigned int rate)
{}

static int snd_sonicvibes_trigger(struct sonicvibes * sonic, int what, int cmd)
{}

static irqreturn_t snd_sonicvibes_interrupt(int irq, void *dev_id)
{}

/*
 *  PCM part
 */

static int snd_sonicvibes_playback_trigger(struct snd_pcm_substream *substream,
					   int cmd)
{}

static int snd_sonicvibes_capture_trigger(struct snd_pcm_substream *substream,
					  int cmd)
{}

static int snd_sonicvibes_playback_prepare(struct snd_pcm_substream *substream)
{}

static int snd_sonicvibes_capture_prepare(struct snd_pcm_substream *substream)
{}

static snd_pcm_uframes_t snd_sonicvibes_playback_pointer(struct snd_pcm_substream *substream)
{}

static snd_pcm_uframes_t snd_sonicvibes_capture_pointer(struct snd_pcm_substream *substream)
{}

static const struct snd_pcm_hardware snd_sonicvibes_playback =;

static const struct snd_pcm_hardware snd_sonicvibes_capture =;

static int snd_sonicvibes_playback_open(struct snd_pcm_substream *substream)
{}

static int snd_sonicvibes_capture_open(struct snd_pcm_substream *substream)
{}

static int snd_sonicvibes_playback_close(struct snd_pcm_substream *substream)
{}

static int snd_sonicvibes_capture_close(struct snd_pcm_substream *substream)
{}

static const struct snd_pcm_ops snd_sonicvibes_playback_ops =;

static const struct snd_pcm_ops snd_sonicvibes_capture_ops =;

static int snd_sonicvibes_pcm(struct sonicvibes *sonic, int device)
{}

/*
 *  Mixer part
 */

#define SONICVIBES_MUX(xname, xindex)

static int snd_sonicvibes_info_mux(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
{}

static int snd_sonicvibes_get_mux(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
{}

static int snd_sonicvibes_put_mux(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
{}

#define SONICVIBES_SINGLE(xname, xindex, reg, shift, mask, invert)

static int snd_sonicvibes_info_single(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
{}

static int snd_sonicvibes_get_single(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
{}

static int snd_sonicvibes_put_single(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
{}

#define SONICVIBES_DOUBLE(xname, xindex, left_reg, right_reg, shift_left, shift_right, mask, invert)

static int snd_sonicvibes_info_double(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
{}

static int snd_sonicvibes_get_double(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
{}

static int snd_sonicvibes_put_double(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
{}

static const struct snd_kcontrol_new snd_sonicvibes_controls[] =;

static void snd_sonicvibes_master_free(struct snd_kcontrol *kcontrol)
{}

static int snd_sonicvibes_mixer(struct sonicvibes *sonic)
{}

/*

 */

static void snd_sonicvibes_proc_read(struct snd_info_entry *entry, 
				     struct snd_info_buffer *buffer)
{}

static void snd_sonicvibes_proc_init(struct sonicvibes *sonic)
{}

/*

 */

#ifdef SUPPORT_JOYSTICK
static const struct snd_kcontrol_new snd_sonicvibes_game_control =;

static int snd_sonicvibes_create_gameport(struct sonicvibes *sonic)
{}

static void snd_sonicvibes_free_gameport(struct sonicvibes *sonic)
{}
#else
static inline int snd_sonicvibes_create_gameport(struct sonicvibes *sonic) { return -ENOSYS; }
static inline void snd_sonicvibes_free_gameport(struct sonicvibes *sonic) { }
#endif

static void snd_sonicvibes_free(struct snd_card *card)
{}

static int snd_sonicvibes_create(struct snd_card *card,
				 struct pci_dev *pci,
				 int reverb,
				 int mge)
{}

/*
 *  MIDI section
 */

static const struct snd_kcontrol_new snd_sonicvibes_midi_controls[] =;

static int snd_sonicvibes_midi_input_open(struct snd_mpu401 * mpu)
{}

static void snd_sonicvibes_midi_input_close(struct snd_mpu401 * mpu)
{}

static int snd_sonicvibes_midi(struct sonicvibes *sonic,
			       struct snd_rawmidi *rmidi)
{}

static int __snd_sonic_probe(struct pci_dev *pci,
			     const struct pci_device_id *pci_id)
{}

static int snd_sonic_probe(struct pci_dev *pci,
			   const struct pci_device_id *pci_id)
{}

static struct pci_driver sonicvibes_driver =;

module_pci_driver();