linux/sound/pci/als4000.c

// SPDX-License-Identifier: GPL-2.0-or-later
/*
 *  card-als4000.c - driver for Avance Logic ALS4000 based soundcards.
 *  Copyright (C) 2000 by Bart Hartgers <[email protected]>,
 *			  Jaroslav Kysela <[email protected]>
 *  Copyright (C) 2002, 2008 by Andreas Mohr <[email protected]>
 *
 *  Framework borrowed from Massimo Piccioni's card-als100.c.
 *
 * NOTES
 *
 *  Since Avance does not provide any meaningful documentation, and I
 *  bought an ALS4000 based soundcard, I was forced to base this driver
 *  on reverse engineering.
 *
 *  Note: this is no longer true (thank you!):
 *  pretty verbose chip docu (ALS4000a.PDF) can be found on the ALSA web site.
 *  Page numbers stated anywhere below with the "SPECS_PAGE:" tag
 *  refer to: ALS4000a.PDF specs Ver 1.0, May 28th, 1998.
 *
 *  The ALS4000 seems to be the PCI-cousin of the ALS100. It contains an
 *  ALS100-like SB DSP/mixer, an OPL3 synth, a MPU401 and a gameport 
 *  interface. These subsystems can be mapped into ISA io-port space, 
 *  using the PCI-interface. In addition, the PCI-bit provides DMA and IRQ 
 *  services to the subsystems.
 * 
 * While ALS4000 is very similar to a SoundBlaster, the differences in
 * DMA and capturing require more changes to the SoundBlaster than
 * desirable, so I made this separate driver.
 * 
 * The ALS4000 can do real full duplex playback/capture.
 *
 * FMDAC:
 * - 0x4f -> port 0x14
 * - port 0x15 |= 1
 *
 * Enable/disable 3D sound:
 * - 0x50 -> port 0x14
 * - change bit 6 (0x40) of port 0x15
 *
 * Set QSound:
 * - 0xdb -> port 0x14
 * - set port 0x15:
 *   0x3e (mode 3), 0x3c (mode 2), 0x3a (mode 1), 0x38 (mode 0)
 *
 * Set KSound:
 * - value -> some port 0x0c0d
 *
 * ToDo:
 * - by default, don't enable legacy game and use PCI game I/O
 * - power management? (card can do voice wakeup according to datasheet!!)
 */

#include <linux/io.h>
#include <linux/init.h>
#include <linux/pci.h>
#include <linux/gameport.h>
#include <linux/module.h>
#include <linux/dma-mapping.h>
#include <sound/core.h>
#include <sound/pcm.h>
#include <sound/rawmidi.h>
#include <sound/mpu401.h>
#include <sound/opl3.h>
#include <sound/sb.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 */
#ifdef SUPPORT_JOYSTICK
static int joystick_port[SNDRV_CARDS];
#endif

module_param_array();
MODULE_PARM_DESC();
module_param_array();
MODULE_PARM_DESC();
module_param_array();
MODULE_PARM_DESC();
#ifdef SUPPORT_JOYSTICK
module_param_hw_array(joystick_port, int, ioport, NULL, 0444);
MODULE_PARM_DESC();
#endif

struct snd_card_als4000 {};

static const struct pci_device_id snd_als4000_ids[] =;

MODULE_DEVICE_TABLE(pci, snd_als4000_ids);

enum als4k_iobase_t {};

enum als4k_iobase_0e_t {};

enum als4k_gcr_t {};

enum als4k_gcr8c_t {};

static inline void snd_als4k_iobase_writeb(unsigned long iobase,
						enum als4k_iobase_t reg,
						u8 val)
{}

static inline void snd_als4k_iobase_writel(unsigned long iobase,
						enum als4k_iobase_t reg,
						u32 val)
{}

static inline u8 snd_als4k_iobase_readb(unsigned long iobase,
						enum als4k_iobase_t reg)
{}

static inline u32 snd_als4k_iobase_readl(unsigned long iobase,
						enum als4k_iobase_t reg)
{}

static inline void snd_als4k_gcr_write_addr(unsigned long iobase,
						 enum als4k_gcr_t reg,
						 u32 val)
{}

static inline void snd_als4k_gcr_write(struct snd_sb *sb,
					 enum als4k_gcr_t reg,
					 u32 val)
{}	

static inline u32 snd_als4k_gcr_read_addr(unsigned long iobase,
						 enum als4k_gcr_t reg)
{}

static inline u32 snd_als4k_gcr_read(struct snd_sb *sb, enum als4k_gcr_t reg)
{}

enum als4k_cr_t {};

enum als4k_cr0_t {};

static inline void snd_als4_cr_write(struct snd_sb *chip,
					enum als4k_cr_t reg,
					u8 data)
{}

static inline u8 snd_als4_cr_read(struct snd_sb *chip,
					enum als4k_cr_t reg)
{}



static void snd_als4000_set_rate(struct snd_sb *chip, unsigned int rate)
{}

static inline void snd_als4000_set_capture_dma(struct snd_sb *chip,
					       dma_addr_t addr, unsigned size)
{}

static inline void snd_als4000_set_playback_dma(struct snd_sb *chip,
						dma_addr_t addr,
						unsigned size)
{}

#define ALS4000_FORMAT_SIGNED
#define ALS4000_FORMAT_16BIT
#define ALS4000_FORMAT_STEREO

static int snd_als4000_get_format(struct snd_pcm_runtime *runtime)
{}

/* structure for setting up playback */
static const struct {} playback_cmd_vals[]=;
#define playback_cmd(chip)

/* structure for setting up capture */
enum {};
static const unsigned char capture_cmd_vals[]=;	
#define capture_cmd(chip)

static int snd_als4000_capture_prepare(struct snd_pcm_substream *substream)
{}

static int snd_als4000_playback_prepare(struct snd_pcm_substream *substream)
{}

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

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

static snd_pcm_uframes_t snd_als4000_capture_pointer(struct snd_pcm_substream *substream)
{}

static snd_pcm_uframes_t snd_als4000_playback_pointer(struct snd_pcm_substream *substream)
{}

/* FIXME: this IRQ routine doesn't really support IRQ sharing (we always
 * return IRQ_HANDLED no matter whether we actually had an IRQ flag or not).
 * ALS4000a.PDF writes that while ACKing IRQ in PCI block will *not* ACK
 * the IRQ in the SB core, ACKing IRQ in SB block *will* ACK the PCI IRQ
 * register (alt_port + ALS4K_IOB_0E_IRQTYPE_SB_CR1E_MPU). Probably something
 * could be optimized here to query/write one register only...
 * And even if both registers need to be queried, then there's still the
 * question of whether it's actually correct to ACK PCI IRQ before reading
 * SB IRQ like we do now, since ALS4000a.PDF mentions that PCI IRQ will *clear*
 * SB IRQ status.
 * (hmm, SPECS_PAGE: 38 mentions it the other way around!)
 * And do we *really* need the lock here for *reading* SB_DSP4_IRQSTATUS??
 * */
static irqreturn_t snd_als4000_interrupt(int irq, void *dev_id)
{}

/*****************************************************************/

static const struct snd_pcm_hardware snd_als4000_playback =;

static const struct snd_pcm_hardware snd_als4000_capture =;

/*****************************************************************/

static int snd_als4000_playback_open(struct snd_pcm_substream *substream)
{}

static int snd_als4000_playback_close(struct snd_pcm_substream *substream)
{}

static int snd_als4000_capture_open(struct snd_pcm_substream *substream)
{}

static int snd_als4000_capture_close(struct snd_pcm_substream *substream)
{}

/******************************************************************/

static const struct snd_pcm_ops snd_als4000_playback_ops =;

static const struct snd_pcm_ops snd_als4000_capture_ops =;

static int snd_als4000_pcm(struct snd_sb *chip, int device)
{}

/******************************************************************/

static void snd_als4000_set_addr(unsigned long iobase,
					unsigned int sb_io,
					unsigned int mpu_io,
					unsigned int opl_io,
					unsigned int game_io)
{}

static void snd_als4000_configure(struct snd_sb *chip)
{}

#ifdef SUPPORT_JOYSTICK
static int snd_als4000_create_gameport(struct snd_card_als4000 *acard, int dev)
{}

static void snd_als4000_free_gameport(struct snd_card_als4000 *acard)
{}
#else
static inline int snd_als4000_create_gameport(struct snd_card_als4000 *acard, int dev) { return -ENOSYS; }
static inline void snd_als4000_free_gameport(struct snd_card_als4000 *acard) { }
#endif

static void snd_card_als4000_free( struct snd_card *card )
{}

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

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

static int snd_als4000_suspend(struct device *dev)
{}

static int snd_als4000_resume(struct device *dev)
{}

static DEFINE_SIMPLE_DEV_PM_OPS(snd_als4000_pm, snd_als4000_suspend, snd_als4000_resume);

static struct pci_driver als4000_driver =;

module_pci_driver();