linux/sound/pci/atiixp_modem.c

// SPDX-License-Identifier: GPL-2.0-or-later
/*
 *   ALSA driver for ATI IXP 150/200/250 AC97 modem controllers
 *
 *	Copyright (c) 2004 Takashi Iwai <[email protected]>
 */

#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/module.h>
#include <linux/mutex.h>
#include <sound/core.h>
#include <sound/pcm.h>
#include <sound/pcm_params.h>
#include <sound/info.h>
#include <sound/ac97_codec.h>
#include <sound/initval.h>

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

static int index =; /* Exclude the first card */
static char *id =;	/* ID for this card */
static int ac97_clock =;

module_param(index, int, 0444);
MODULE_PARM_DESC();
module_param(id, charp, 0444);
MODULE_PARM_DESC();
module_param(ac97_clock, int, 0444);
MODULE_PARM_DESC();

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


/*
 */

#define ATI_REG_ISR
#define ATI_REG_ISR_MODEM_IN_XRUN
#define ATI_REG_ISR_MODEM_IN_STATUS
#define ATI_REG_ISR_MODEM_OUT1_XRUN
#define ATI_REG_ISR_MODEM_OUT1_STATUS
#define ATI_REG_ISR_MODEM_OUT2_XRUN
#define ATI_REG_ISR_MODEM_OUT2_STATUS
#define ATI_REG_ISR_MODEM_OUT3_XRUN
#define ATI_REG_ISR_MODEM_OUT3_STATUS
#define ATI_REG_ISR_PHYS_INTR
#define ATI_REG_ISR_PHYS_MISMATCH
#define ATI_REG_ISR_CODEC0_NOT_READY
#define ATI_REG_ISR_CODEC1_NOT_READY
#define ATI_REG_ISR_CODEC2_NOT_READY
#define ATI_REG_ISR_NEW_FRAME
#define ATI_REG_ISR_MODEM_GPIO_DATA

#define ATI_REG_IER
#define ATI_REG_IER_MODEM_IN_XRUN_EN
#define ATI_REG_IER_MODEM_STATUS_EN
#define ATI_REG_IER_MODEM_OUT1_XRUN_EN
#define ATI_REG_IER_MODEM_OUT2_XRUN_EN
#define ATI_REG_IER_MODEM_OUT3_XRUN_EN
#define ATI_REG_IER_PHYS_INTR_EN
#define ATI_REG_IER_PHYS_MISMATCH_EN
#define ATI_REG_IER_CODEC0_INTR_EN
#define ATI_REG_IER_CODEC1_INTR_EN
#define ATI_REG_IER_CODEC2_INTR_EN
#define ATI_REG_IER_NEW_FRAME_EN
#define ATI_REG_IER_MODEM_GPIO_DATA_EN
#define ATI_REG_IER_MODEM_SET_BUS_BUSY

#define ATI_REG_CMD
#define ATI_REG_CMD_POWERDOWN
#define ATI_REG_CMD_MODEM_RECEIVE_EN
#define ATI_REG_CMD_MODEM_SEND1_EN
#define ATI_REG_CMD_MODEM_SEND2_EN
#define ATI_REG_CMD_MODEM_SEND3_EN
#define ATI_REG_CMD_MODEM_STATUS_MEM
#define ATI_REG_CMD_MODEM_IN_DMA_EN
#define ATI_REG_CMD_MODEM_OUT_DMA1_EN
#define ATI_REG_CMD_MODEM_OUT_DMA2_EN
#define ATI_REG_CMD_MODEM_OUT_DMA3_EN
#define ATI_REG_CMD_AUDIO_PRESENT
#define ATI_REG_CMD_MODEM_GPIO_THRU_DMA
#define ATI_REG_CMD_LOOPBACK_EN
#define ATI_REG_CMD_PACKED_DIS
#define ATI_REG_CMD_BURST_EN
#define ATI_REG_CMD_PANIC_EN
#define ATI_REG_CMD_MODEM_PRESENT
#define ATI_REG_CMD_ACLINK_ACTIVE
#define ATI_REG_CMD_AC_SOFT_RESET
#define ATI_REG_CMD_AC_SYNC
#define ATI_REG_CMD_AC_RESET

#define ATI_REG_PHYS_OUT_ADDR
#define ATI_REG_PHYS_OUT_CODEC_MASK
#define ATI_REG_PHYS_OUT_RW
#define ATI_REG_PHYS_OUT_ADDR_EN
#define ATI_REG_PHYS_OUT_ADDR_SHIFT
#define ATI_REG_PHYS_OUT_DATA_SHIFT

#define ATI_REG_PHYS_IN_ADDR
#define ATI_REG_PHYS_IN_READ_FLAG
#define ATI_REG_PHYS_IN_ADDR_SHIFT
#define ATI_REG_PHYS_IN_DATA_SHIFT

#define ATI_REG_SLOTREQ

#define ATI_REG_COUNTER
#define ATI_REG_COUNTER_SLOT
#define ATI_REG_COUNTER_BITCLOCK

#define ATI_REG_IN_FIFO_THRESHOLD

#define ATI_REG_MODEM_IN_DMA_LINKPTR
#define ATI_REG_MODEM_IN_DMA_DT_START
#define ATI_REG_MODEM_IN_DMA_DT_NEXT
#define ATI_REG_MODEM_IN_DMA_DT_CUR
#define ATI_REG_MODEM_IN_DMA_DT_SIZE
#define ATI_REG_MODEM_OUT_FIFO
#define ATI_REG_MODEM_OUT1_DMA_THRESHOLD_MASK
#define ATI_REG_MODEM_OUT1_DMA_THRESHOLD_SHIFT
#define ATI_REG_MODEM_OUT_DMA1_LINKPTR
#define ATI_REG_MODEM_OUT_DMA2_LINKPTR
#define ATI_REG_MODEM_OUT_DMA3_LINKPTR
#define ATI_REG_MODEM_OUT_DMA1_DT_START
#define ATI_REG_MODEM_OUT_DMA1_DT_NEXT
#define ATI_REG_MODEM_OUT_DMA1_DT_CUR
#define ATI_REG_MODEM_OUT_DMA2_DT_START
#define ATI_REG_MODEM_OUT_DMA2_DT_NEXT
#define ATI_REG_MODEM_OUT_DMA2_DT_CUR
#define ATI_REG_MODEM_OUT_DMA3_DT_START
#define ATI_REG_MODEM_OUT_DMA3_DT_NEXT
#define ATI_REG_MODEM_OUT_DMA3_DT_CUR
#define ATI_REG_MODEM_OUT_DMA12_DT_SIZE
#define ATI_REG_MODEM_OUT_DMA3_DT_SIZE
#define ATI_REG_MODEM_OUT_FIFO_USED
#define ATI_REG_MODEM_OUT_GPIO
#define ATI_REG_MODEM_OUT_GPIO_EN
#define ATI_REG_MODEM_OUT_GPIO_DATA_SHIFT
#define ATI_REG_MODEM_IN_GPIO

#define ATI_REG_MODEM_MIRROR
#define ATI_REG_AUDIO_MIRROR

#define ATI_REG_MODEM_FIFO_FLUSH
#define ATI_REG_MODEM_FIFO_OUT1_FLUSH
#define ATI_REG_MODEM_FIFO_OUT2_FLUSH
#define ATI_REG_MODEM_FIFO_OUT3_FLUSH
#define ATI_REG_MODEM_FIFO_IN_FLUSH

/* LINKPTR */
#define ATI_REG_LINKPTR_EN

#define ATI_MAX_DESCRIPTORS


struct atiixp_modem;

/*
 * DMA packate descriptor
 */

struct atiixp_dma_desc {};

/*
 * stream enum
 */
enum {}; /* DMAs */
enum {}; /* AC97 pcm slots */
enum {}; /* pcm devices */

#define NUM_ATI_CODECS


/*
 * constants and callbacks for each DMA type
 */
struct atiixp_dma_ops {};

/*
 * DMA stream
 */
struct atiixp_dma {};

/*
 * ATI IXP chip
 */
struct atiixp_modem {};


/*
 */
static const struct pci_device_id snd_atiixp_ids[] =;

MODULE_DEVICE_TABLE(pci, snd_atiixp_ids);


/*
 * lowlevel functions
 */

/*
 * update the bits of the given register.
 * return 1 if the bits changed.
 */
static int snd_atiixp_update_bits(struct atiixp_modem *chip, unsigned int reg,
				  unsigned int mask, unsigned int value)
{}

/*
 * macros for easy use
 */
#define atiixp_write(chip,reg,value)
#define atiixp_read(chip,reg)
#define atiixp_update(chip,reg,mask,val)

/*
 * handling DMA packets
 *
 * we allocate a linear buffer for the DMA, and split it to  each packet.
 * in a future version, a scatter-gather buffer should be implemented.
 */

#define ATI_DESC_LIST_SIZE

/*
 * build packets ring for the given buffer size.
 *
 * IXP handles the buffer descriptors, which are connected as a linked
 * list.  although we can change the list dynamically, in this version,
 * a static RING of buffer descriptors is used.
 *
 * the ring is built in this function, and is set up to the hardware. 
 */
static int atiixp_build_dma_packets(struct atiixp_modem *chip,
				    struct atiixp_dma *dma,
				    struct snd_pcm_substream *substream,
				    unsigned int periods,
				    unsigned int period_bytes)
{}

/*
 * remove the ring buffer and release it if assigned
 */
static void atiixp_clear_dma_packets(struct atiixp_modem *chip,
				     struct atiixp_dma *dma,
				     struct snd_pcm_substream *substream)
{}

/*
 * AC97 interface
 */
static int snd_atiixp_acquire_codec(struct atiixp_modem *chip)
{}

static unsigned short snd_atiixp_codec_read(struct atiixp_modem *chip,
					    unsigned short codec,
					    unsigned short reg)
{}


static void snd_atiixp_codec_write(struct atiixp_modem *chip,
				   unsigned short codec,
				   unsigned short reg, unsigned short val)
{}


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

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

/*
 * reset AC link
 */
static int snd_atiixp_aclink_reset(struct atiixp_modem *chip)
{}

static int snd_atiixp_aclink_down(struct atiixp_modem *chip)
{}

/*
 * auto-detection of codecs
 *
 * the IXP chip can generate interrupts for the non-existing codecs.
 * NEW_FRAME interrupt is used to make sure that the interrupt is generated
 * even if all three codecs are connected.
 */

#define ALL_CODEC_NOT_READY
#define CODEC_CHECK_BITS

static int snd_atiixp_codec_detect(struct atiixp_modem *chip)
{}


/*
 * enable DMA and irqs
 */
static int snd_atiixp_chip_start(struct atiixp_modem *chip)
{}


/*
 * disable DMA and IRQs
 */
static int snd_atiixp_chip_stop(struct atiixp_modem *chip)
{}


/*
 * PCM section
 */

/*
 * pointer callback simplly reads XXX_DMA_DT_CUR register as the current
 * position.  when SG-buffer is implemented, the offset must be calculated
 * correctly...
 */
static snd_pcm_uframes_t snd_atiixp_pcm_pointer(struct snd_pcm_substream *substream)
{}

/*
 * XRUN detected, and stop the PCM substream
 */
static void snd_atiixp_xrun_dma(struct atiixp_modem *chip,
				struct atiixp_dma *dma)
{}

/*
 * the period ack.  update the substream.
 */
static void snd_atiixp_update_dma(struct atiixp_modem *chip,
				  struct atiixp_dma *dma)
{}

/* set BUS_BUSY interrupt bit if any DMA is running */
/* call with spinlock held */
static void snd_atiixp_check_bus_busy(struct atiixp_modem *chip)
{}

/* common trigger callback
 * calling the lowlevel callbacks in it
 */
static int snd_atiixp_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
{}


/*
 * lowlevel callbacks for each DMA type
 *
 * every callback is supposed to be called in chip->reg_lock spinlock
 */

/* flush FIFO of analog OUT DMA */
static void atiixp_out_flush_dma(struct atiixp_modem *chip)
{}

/* enable/disable analog OUT DMA */
static void atiixp_out_enable_dma(struct atiixp_modem *chip, int on)
{}

/* start/stop transfer over OUT DMA */
static void atiixp_out_enable_transfer(struct atiixp_modem *chip, int on)
{}

/* enable/disable analog IN DMA */
static void atiixp_in_enable_dma(struct atiixp_modem *chip, int on)
{}

/* start/stop analog IN DMA */
static void atiixp_in_enable_transfer(struct atiixp_modem *chip, int on)
{}

/* flush FIFO of analog IN DMA */
static void atiixp_in_flush_dma(struct atiixp_modem *chip)
{}

/* set up slots and formats for analog OUT */
static int snd_atiixp_playback_prepare(struct snd_pcm_substream *substream)
{}

/* set up slots and formats for analog IN */
static int snd_atiixp_capture_prepare(struct snd_pcm_substream *substream)
{}

/*
 * hw_params - allocate the buffer and set up buffer descriptors
 */
static int snd_atiixp_pcm_hw_params(struct snd_pcm_substream *substream,
				   struct snd_pcm_hw_params *hw_params)
{}

static int snd_atiixp_pcm_hw_free(struct snd_pcm_substream *substream)
{}


/*
 * pcm hardware definition, identical for all DMA types
 */
static const struct snd_pcm_hardware snd_atiixp_pcm_hw =;

static int snd_atiixp_pcm_open(struct snd_pcm_substream *substream,
			       struct atiixp_dma *dma, int pcm_type)
{}

static int snd_atiixp_pcm_close(struct snd_pcm_substream *substream,
				struct atiixp_dma *dma)
{}

/*
 */
static int snd_atiixp_playback_open(struct snd_pcm_substream *substream)
{}

static int snd_atiixp_playback_close(struct snd_pcm_substream *substream)
{}

static int snd_atiixp_capture_open(struct snd_pcm_substream *substream)
{}

static int snd_atiixp_capture_close(struct snd_pcm_substream *substream)
{}


/* AC97 playback */
static const struct snd_pcm_ops snd_atiixp_playback_ops =;

/* AC97 capture */
static const struct snd_pcm_ops snd_atiixp_capture_ops =;

static const struct atiixp_dma_ops snd_atiixp_playback_dma_ops =;
	
static const struct atiixp_dma_ops snd_atiixp_capture_dma_ops =;

static int snd_atiixp_pcm_new(struct atiixp_modem *chip)
{}



/*
 * interrupt handler
 */
static irqreturn_t snd_atiixp_interrupt(int irq, void *dev_id)
{}


/*
 * ac97 mixer section
 */

static int snd_atiixp_mixer_new(struct atiixp_modem *chip, int clock)
{}


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

static int snd_atiixp_resume(struct device *dev)
{}

static DEFINE_SIMPLE_DEV_PM_OPS(snd_atiixp_pm, snd_atiixp_suspend, snd_atiixp_resume);

/*
 * proc interface for register dump
 */

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

static void snd_atiixp_proc_init(struct atiixp_modem *chip)
{}


/*
 * destructor
 */

static void snd_atiixp_free(struct snd_card *card)
{}

/*
 * constructor for chip instance
 */
static int snd_atiixp_init(struct snd_card *card, struct pci_dev *pci)
{}


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

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

static struct pci_driver atiixp_modem_driver =;

module_pci_driver();