linux/sound/pci/via82xx.c

// SPDX-License-Identifier: GPL-2.0-or-later
/*
 *   ALSA driver for VIA VT82xx (South Bridge)
 *
 *   VT82C686A/B/C, VT8233A/C, VT8235
 *
 *	Copyright (c) 2000 Jaroslav Kysela <[email protected]>
 *	                   Tjeerd.Mulder <[email protected]>
 *                    2002 Takashi Iwai <[email protected]>
 */

/*
 * Changes:
 *
 * Dec. 19, 2002	Takashi Iwai <[email protected]>
 *	- use the DSX channels for the first pcm playback.
 *	  (on VIA8233, 8233C and 8235 only)
 *	  this will allow you play simultaneously up to 4 streams.
 *	  multi-channel playback is assigned to the second device
 *	  on these chips.
 *	- support the secondary capture (on VIA8233/C,8235)
 *	- SPDIF support
 *	  the DSX3 channel can be used for SPDIF output.
 *	  on VIA8233A, this channel is assigned to the second pcm
 *	  playback.
 *	  the card config of alsa-lib will assign the correct
 *	  device for applications.
 *	- clean up the code, separate low-level initialization
 *	  routines for each chipset.
 *
 * Sep. 26, 2005	Karsten Wiese <[email protected]>
 *	- Optimize position calculation for the 823x chips. 
 */

#include <linux/io.h>
#include <linux/delay.h>
#include <linux/interrupt.h>
#include <linux/init.h>
#include <linux/pci.h>
#include <linux/slab.h>
#include <linux/gameport.h>
#include <linux/module.h>
#include <sound/core.h>
#include <sound/pcm.h>
#include <sound/pcm_params.h>
#include <sound/info.h>
#include <sound/tlv.h>
#include <sound/ac97_codec.h>
#include <sound/mpu401.h>
#include <sound/initval.h>

#if 0
#define POINTER_DEBUG
#endif

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

#if IS_REACHABLE(CONFIG_GAMEPORT)
#define SUPPORT_JOYSTICK
#endif

static int index =;	/* Index 0-MAX */
static char *id =;	/* ID for this card */
static long mpu_port;
#ifdef SUPPORT_JOYSTICK
static bool joystick;
#endif
static int ac97_clock =;
static char *ac97_quirk;
static int dxs_support;
static int dxs_init_volume =;
static int nodelay;

module_param(index, int, 0444);
MODULE_PARM_DESC();
module_param(id, charp, 0444);
MODULE_PARM_DESC();
module_param_hw(mpu_port, long, ioport, 0444);
MODULE_PARM_DESC();
#ifdef SUPPORT_JOYSTICK
module_param(joystick, bool, 0444);
MODULE_PARM_DESC();
#endif
module_param(ac97_clock, int, 0444);
MODULE_PARM_DESC();
module_param(ac97_quirk, charp, 0444);
MODULE_PARM_DESC();
module_param(dxs_support, int, 0444);
MODULE_PARM_DESC();
module_param(dxs_init_volume, int, 0644);
MODULE_PARM_DESC();
module_param(nodelay, int, 0444);
MODULE_PARM_DESC();

/* just for backward compatibility */
static bool enable;
module_param(enable, bool, 0444);


/* revision numbers for via686 */
#define VIA_REV_686_A
#define VIA_REV_686_B
#define VIA_REV_686_C
#define VIA_REV_686_D
#define VIA_REV_686_E
#define VIA_REV_686_H

/* revision numbers for via8233 */
#define VIA_REV_PRE_8233
#define VIA_REV_8233C
#define VIA_REV_8233
#define VIA_REV_8233A
#define VIA_REV_8235
#define VIA_REV_8237
#define VIA_REV_8251

/*
 *  Direct registers
 */

#define VIAREG(via, x)
#define VIADEV_REG(viadev, x)

/* common offsets */
#define VIA_REG_OFFSET_STATUS
#define VIA_REG_STAT_ACTIVE
#define VIA8233_SHADOW_STAT_ACTIVE
#define VIA_REG_STAT_PAUSED
#define VIA_REG_STAT_TRIGGER_QUEUED
#define VIA_REG_STAT_STOPPED
#define VIA_REG_STAT_EOL
#define VIA_REG_STAT_FLAG
#define VIA_REG_OFFSET_CONTROL
#define VIA_REG_CTRL_START
#define VIA_REG_CTRL_TERMINATE
#define VIA_REG_CTRL_AUTOSTART
#define VIA_REG_CTRL_PAUSE
#define VIA_REG_CTRL_INT_STOP		
#define VIA_REG_CTRL_INT_EOL
#define VIA_REG_CTRL_INT_FLAG
#define VIA_REG_CTRL_RESET
#define VIA_REG_CTRL_INT
#define VIA_REG_OFFSET_TYPE
#define VIA_REG_TYPE_AUTOSTART
#define VIA_REG_TYPE_16BIT
#define VIA_REG_TYPE_STEREO
#define VIA_REG_TYPE_INT_LLINE
#define VIA_REG_TYPE_INT_LSAMPLE
#define VIA_REG_TYPE_INT_LESSONE
#define VIA_REG_TYPE_INT_MASK
#define VIA_REG_TYPE_INT_EOL
#define VIA_REG_TYPE_INT_FLAG
#define VIA_REG_OFFSET_TABLE_PTR
#define VIA_REG_OFFSET_CURR_PTR
#define VIA_REG_OFFSET_STOP_IDX
#define VIA8233_REG_TYPE_16BIT
#define VIA8233_REG_TYPE_STEREO
#define VIA_REG_OFFSET_CURR_COUNT
#define VIA_REG_OFFSET_CURR_INDEX

#define DEFINE_VIA_REGSET(name,val)

/* playback block */
DEFINE_VIA_REGSET(PLAYBACK, 0x00);
DEFINE_VIA_REGSET(CAPTURE, 0x10);
DEFINE_VIA_REGSET(FM, 0x20);

/* AC'97 */
#define VIA_REG_AC97
#define VIA_REG_AC97_CODEC_ID_MASK
#define VIA_REG_AC97_CODEC_ID_SHIFT
#define VIA_REG_AC97_CODEC_ID_PRIMARY
#define VIA_REG_AC97_CODEC_ID_SECONDARY
#define VIA_REG_AC97_SECONDARY_VALID
#define VIA_REG_AC97_PRIMARY_VALID
#define VIA_REG_AC97_BUSY
#define VIA_REG_AC97_READ
#define VIA_REG_AC97_CMD_SHIFT
#define VIA_REG_AC97_CMD_MASK
#define VIA_REG_AC97_DATA_SHIFT
#define VIA_REG_AC97_DATA_MASK

#define VIA_REG_SGD_SHADOW
/* via686 */
#define VIA_REG_SGD_STAT_PB_FLAG
#define VIA_REG_SGD_STAT_CP_FLAG
#define VIA_REG_SGD_STAT_FM_FLAG
#define VIA_REG_SGD_STAT_PB_EOL
#define VIA_REG_SGD_STAT_CP_EOL
#define VIA_REG_SGD_STAT_FM_EOL
#define VIA_REG_SGD_STAT_PB_STOP
#define VIA_REG_SGD_STAT_CP_STOP
#define VIA_REG_SGD_STAT_FM_STOP
#define VIA_REG_SGD_STAT_PB_ACTIVE
#define VIA_REG_SGD_STAT_CP_ACTIVE
#define VIA_REG_SGD_STAT_FM_ACTIVE
/* via8233 */
#define VIA8233_REG_SGD_STAT_FLAG
#define VIA8233_REG_SGD_STAT_EOL
#define VIA8233_REG_SGD_STAT_STOP
#define VIA8233_REG_SGD_STAT_ACTIVE
#define VIA8233_INTR_MASK(chan)
#define VIA8233_REG_SGD_CHAN_SDX
#define VIA8233_REG_SGD_CHAN_MULTI
#define VIA8233_REG_SGD_CHAN_REC
#define VIA8233_REG_SGD_CHAN_REC1

#define VIA_REG_GPI_STATUS
#define VIA_REG_GPI_INTR

/* multi-channel and capture registers for via8233 */
DEFINE_VIA_REGSET(MULTPLAY, 0x40);
DEFINE_VIA_REGSET(CAPTURE_8233, 0x60);

/* via8233-specific registers */
#define VIA_REG_OFS_PLAYBACK_VOLUME_L
#define VIA_REG_OFS_PLAYBACK_VOLUME_R
#define VIA_REG_OFS_MULTPLAY_FORMAT
#define VIA_REG_MULTPLAY_FMT_8BIT
#define VIA_REG_MULTPLAY_FMT_16BIT
#define VIA_REG_MULTPLAY_FMT_CH_MASK
#define VIA_REG_OFS_CAPTURE_FIFO
#define VIA_REG_CAPTURE_FIFO_ENABLE

#define VIA_DXS_MAX_VOLUME

#define VIA_REG_CAPTURE_CHANNEL
#define VIA_REG_CAPTURE_CHANNEL_MIC
#define VIA_REG_CAPTURE_CHANNEL_LINE
#define VIA_REG_CAPTURE_SELECT_CODEC

#define VIA_TBL_BIT_FLAG
#define VIA_TBL_BIT_EOL

/* pci space */
#define VIA_ACLINK_STAT
#define VIA_ACLINK_C11_READY
#define VIA_ACLINK_C10_READY
#define VIA_ACLINK_C01_READY
#define VIA_ACLINK_LOWPOWER
#define VIA_ACLINK_C00_READY
#define VIA_ACLINK_CTRL
#define VIA_ACLINK_CTRL_ENABLE
#define VIA_ACLINK_CTRL_RESET
#define VIA_ACLINK_CTRL_SYNC
#define VIA_ACLINK_CTRL_SDO
#define VIA_ACLINK_CTRL_VRA
#define VIA_ACLINK_CTRL_PCM
#define VIA_ACLINK_CTRL_FM
#define VIA_ACLINK_CTRL_SB
#define VIA_ACLINK_CTRL_INIT
#define VIA_FUNC_ENABLE
#define VIA_FUNC_MIDI_PNP
#define VIA_FUNC_MIDI_IRQMASK
#define VIA_FUNC_RX2C_WRITE
#define VIA_FUNC_SB_FIFO_EMPTY
#define VIA_FUNC_ENABLE_GAME
#define VIA_FUNC_ENABLE_FM
#define VIA_FUNC_ENABLE_MIDI
#define VIA_FUNC_ENABLE_SB
#define VIA_PNP_CONTROL
#define VIA_FM_NMI_CTRL
#define VIA8233_VOLCHG_CTRL
#define VIA8233_SPDIF_CTRL
#define VIA8233_SPDIF_DX3
#define VIA8233_SPDIF_SLOT_MASK
#define VIA8233_SPDIF_SLOT_1011
#define VIA8233_SPDIF_SLOT_34
#define VIA8233_SPDIF_SLOT_78
#define VIA8233_SPDIF_SLOT_69

/*
 */

#define VIA_DXS_AUTO
#define VIA_DXS_ENABLE
#define VIA_DXS_DISABLE
#define VIA_DXS_48K
#define VIA_DXS_NO_VRA
#define VIA_DXS_SRC


/*
 * pcm stream
 */

struct snd_via_sg_table {} ;

#define VIA_TABLE_SIZE
#define VIA_MAX_BUFSIZE

struct viadev {};


enum {};
enum {};

#define VIA_MAX_DEVS

struct via_rate_lock {};

struct via82xx {};

static const struct pci_device_id snd_via82xx_ids[] =;

MODULE_DEVICE_TABLE(pci, snd_via82xx_ids);

/*
 */

/*
 * allocate and initialize the descriptor buffers
 * periods = number of periods
 * fragsize = period size in bytes
 */
static int build_via_table(struct viadev *dev, struct snd_pcm_substream *substream,
			   struct pci_dev *pci,
			   unsigned int periods, unsigned int fragsize)
{}


static int clean_via_table(struct viadev *dev, struct snd_pcm_substream *substream,
			   struct pci_dev *pci)
{}

/*
 *  Basic I/O
 */

static inline unsigned int snd_via82xx_codec_xread(struct via82xx *chip)
{}
 
static inline void snd_via82xx_codec_xwrite(struct via82xx *chip, unsigned int val)
{}
 
static int snd_via82xx_codec_ready(struct via82xx *chip, int secondary)
{}
 
static int snd_via82xx_codec_valid(struct via82xx *chip, int secondary)
{}
 
static void snd_via82xx_codec_wait(struct snd_ac97 *ac97)
{}

static void snd_via82xx_codec_write(struct snd_ac97 *ac97,
				    unsigned short reg,
				    unsigned short val)
{}

static unsigned short snd_via82xx_codec_read(struct snd_ac97 *ac97, unsigned short reg)
{}

static void snd_via82xx_channel_reset(struct via82xx *chip, struct viadev *viadev)
{}


/*
 *  Interrupt handler
 *  Used for 686 and 8233A
 */
static irqreturn_t snd_via686_interrupt(int irq, void *dev_id)
{}

/*
 *  Interrupt handler
 */
static irqreturn_t snd_via8233_interrupt(int irq, void *dev_id)
{}

/*
 *  PCM callbacks
 */

/*
 * trigger callback
 */
static int snd_via82xx_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
{}


/*
 * pointer callbacks
 */

/*
 * calculate the linear position at the given sg-buffer index and the rest count
 */

#define check_invalid_pos(viadev,pos)

static inline unsigned int calc_linear_pos(struct via82xx *chip,
					   struct viadev *viadev,
					   unsigned int idx,
					   unsigned int count)
{}

/*
 * get the current pointer on via686
 */
static snd_pcm_uframes_t snd_via686_pcm_pointer(struct snd_pcm_substream *substream)
{}

/*
 * get the current pointer on via823x
 */
static snd_pcm_uframes_t snd_via8233_pcm_pointer(struct snd_pcm_substream *substream)
{}


/*
 * hw_params callback:
 * allocate the buffer and build up the buffer description table
 */
static int snd_via82xx_hw_params(struct snd_pcm_substream *substream,
				 struct snd_pcm_hw_params *hw_params)
{}

/*
 * hw_free callback:
 * clean up the buffer description table and release the buffer
 */
static int snd_via82xx_hw_free(struct snd_pcm_substream *substream)
{}


/*
 * set up the table pointer
 */
static void snd_via82xx_set_table_ptr(struct via82xx *chip, struct viadev *viadev)
{}

/*
 * prepare callback for playback and capture on via686
 */
static void via686_setup_format(struct via82xx *chip, struct viadev *viadev,
				struct snd_pcm_runtime *runtime)
{}

static int snd_via686_playback_prepare(struct snd_pcm_substream *substream)
{}

static int snd_via686_capture_prepare(struct snd_pcm_substream *substream)
{}

/*
 * lock the current rate
 */
static int via_lock_rate(struct via_rate_lock *rec, int rate)
{}

/*
 * prepare callback for DSX playback on via823x
 */
static int snd_via8233_playback_prepare(struct snd_pcm_substream *substream)
{}

/*
 * prepare callback for multi-channel playback on via823x
 */
static int snd_via8233_multi_prepare(struct snd_pcm_substream *substream)
{}

/*
 * prepare callback for capture on via823x
 */
static int snd_via8233_capture_prepare(struct snd_pcm_substream *substream)
{}


/*
 * pcm hardware definition, identical for both playback and capture
 */
static const struct snd_pcm_hardware snd_via82xx_hw =;


/*
 * open callback skeleton
 */
static int snd_via82xx_pcm_open(struct via82xx *chip, struct viadev *viadev,
				struct snd_pcm_substream *substream)
{}


/*
 * open callback for playback on via686
 */
static int snd_via686_playback_open(struct snd_pcm_substream *substream)
{}

/*
 * open callback for playback on via823x DXS
 */
static int snd_via8233_playback_open(struct snd_pcm_substream *substream)
{}

/*
 * open callback for playback on via823x multi-channel
 */
static int snd_via8233_multi_open(struct snd_pcm_substream *substream)
{}

/*
 * open callback for capture on via686 and via823x
 */
static int snd_via82xx_capture_open(struct snd_pcm_substream *substream)
{}

/*
 * close callback
 */
static int snd_via82xx_pcm_close(struct snd_pcm_substream *substream)
{}

static int snd_via8233_playback_close(struct snd_pcm_substream *substream)
{}


/* via686 playback callbacks */
static const struct snd_pcm_ops snd_via686_playback_ops =;

/* via686 capture callbacks */
static const struct snd_pcm_ops snd_via686_capture_ops =;

/* via823x DSX playback callbacks */
static const struct snd_pcm_ops snd_via8233_playback_ops =;

/* via823x multi-channel playback callbacks */
static const struct snd_pcm_ops snd_via8233_multi_ops =;

/* via823x capture callbacks */
static const struct snd_pcm_ops snd_via8233_capture_ops =;


static void init_viadev(struct via82xx *chip, int idx, unsigned int reg_offset,
			int shadow_pos, int direction)
{}

/*
 * create pcm instances for VIA8233, 8233C and 8235 (not 8233A)
 */
static int snd_via8233_pcm_new(struct via82xx *chip)
{}

/*
 * create pcm instances for VIA8233A
 */
static int snd_via8233a_pcm_new(struct via82xx *chip)
{}

/*
 * create a pcm instance for via686a/b
 */
static int snd_via686_pcm_new(struct via82xx *chip)
{}


/*
 *  Mixer part
 */

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

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

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

static struct snd_kcontrol_new snd_via8233_capture_source =;

#define snd_via8233_dxs3_spdif_info

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

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

static const struct snd_kcontrol_new snd_via8233_dxs3_spdif_control =;

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

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

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

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

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

static const DECLARE_TLV_DB_SCALE(db_scale_dxs, -4650, 150, 1);

static const struct snd_kcontrol_new snd_via8233_pcmdxs_volume_control =;

static const struct snd_kcontrol_new snd_via8233_dxs_volume_control =;

/*
 */

static void snd_via82xx_mixer_free_ac97_bus(struct snd_ac97_bus *bus)
{}

static void snd_via82xx_mixer_free_ac97(struct snd_ac97 *ac97)
{}

static const struct ac97_quirk ac97_quirks[] =;

static int snd_via82xx_mixer_new(struct via82xx *chip, const char *quirk_override)
{}

#ifdef SUPPORT_JOYSTICK
#define JOYSTICK_ADDR
static int snd_via686_create_gameport(struct via82xx *chip, unsigned char *legacy)
{}

static void snd_via686_free_gameport(struct via82xx *chip)
{}
#else
static inline int snd_via686_create_gameport(struct via82xx *chip, unsigned char *legacy)
{
	return -ENOSYS;
}
static inline void snd_via686_free_gameport(struct via82xx *chip) { }
#endif


/*
 *
 */

static int snd_via8233_init_misc(struct via82xx *chip)
{}

static int snd_via686_init_misc(struct via82xx *chip)
{}


/*
 * proc interface
 */
static void snd_via82xx_proc_read(struct snd_info_entry *entry,
				  struct snd_info_buffer *buffer)
{}

static void snd_via82xx_proc_init(struct via82xx *chip)
{}

/*
 *
 */

static int snd_via82xx_chip_init(struct via82xx *chip)
{}

/*
 * power management
 */
static int snd_via82xx_suspend(struct device *dev)
{}

static int snd_via82xx_resume(struct device *dev)
{}

static DEFINE_SIMPLE_DEV_PM_OPS(snd_via82xx_pm, snd_via82xx_suspend, snd_via82xx_resume);

static void snd_via82xx_free(struct snd_card *card)
{}

static int snd_via82xx_create(struct snd_card *card,
			      struct pci_dev *pci,
			      int chip_type,
			      int revision,
			      unsigned int ac97_clock)
{}

struct via823x_info {};
static const struct via823x_info via823x_cards[] =;

/*
 * auto detection of DXS channel supports.
 */

static const struct snd_pci_quirk dxs_allowlist[] =;

static int check_dxs_list(struct pci_dev *pci, int revision)
{
	const struct snd_pci_quirk *w;

	w = snd_pci_quirk_lookup(pci, dxs_allowlist);
	if (w) {
		dev_dbg(&pci->dev, "DXS allow list for %s found\n",
			    snd_pci_quirk_name(w));
		return w->value;
	}

	/* for newer revision, default to DXS_SRC */
	if (revision >= VIA_REV_8235)
		return VIA_DXS_SRC;

	/*
	 * not detected, try 48k rate only to be sure.
	 */
	dev_info(&pci->dev, "Assuming DXS channels with 48k fixed sample rate.\n");
	dev_info(&pci->dev, "         Please try dxs_support=5 option\n");
	dev_info(&pci->dev, "         and report if it works on your machine.\n");
	dev_info(&pci->dev, "         For more details, read ALSA-Configuration.txt.\n");
	return VIA_DXS_48K;
};

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

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

static struct pci_driver via82xx_driver =;

module_pci_driver();