#include <linux/init.h>
#include <linux/err.h>
#include <linux/isa.h>
#include <linux/delay.h>
#include <linux/pnp.h>
#include <linux/module.h>
#include <linux/io.h>
#include <asm/dma.h>
#include <sound/core.h>
#include <sound/tlv.h>
#include <sound/wss.h>
#include <sound/mpu401.h>
#include <sound/opl3.h>
#ifndef OPTi93X
#include <sound/opl4.h>
#endif
#define SNDRV_LEGACY_FIND_FREE_IOPORT
#define SNDRV_LEGACY_FIND_FREE_IRQ
#define SNDRV_LEGACY_FIND_FREE_DMA
#include <sound/initval.h>
MODULE_AUTHOR(…) …;
MODULE_LICENSE(…) …;
#ifdef OPTi93X
MODULE_DESCRIPTION("OPTi93X");
#else
#ifdef CS4231
MODULE_DESCRIPTION("OPTi92X - CS4231");
#else
MODULE_DESCRIPTION(…) …;
#endif
#endif
static int index = …;
static char *id = …;
#ifdef CONFIG_PNP
static bool isapnp = …;
#endif
static long port = …;
static long mpu_port = …;
static long fm_port = …;
static int irq = …;
static int mpu_irq = …;
static int dma1 = …;
#if defined(CS4231) || defined(OPTi93X)
static int dma2 = SNDRV_DEFAULT_DMA1;
#endif
module_param(index, int, 0444);
MODULE_PARM_DESC(…) …;
module_param(id, charp, 0444);
MODULE_PARM_DESC(…) …;
#ifdef CONFIG_PNP
module_param(isapnp, bool, 0444);
MODULE_PARM_DESC(…) …;
#endif
module_param_hw(port, long, ioport, 0444);
MODULE_PARM_DESC(…) …;
module_param_hw(mpu_port, long, ioport, 0444);
MODULE_PARM_DESC(…) …;
module_param_hw(fm_port, long, ioport, 0444);
MODULE_PARM_DESC(…) …;
module_param_hw(irq, int, irq, 0444);
MODULE_PARM_DESC(…) …;
module_param_hw(mpu_irq, int, irq, 0444);
MODULE_PARM_DESC(…) …;
module_param_hw(dma1, int, dma, 0444);
MODULE_PARM_DESC(…) …;
#if defined(CS4231) || defined(OPTi93X)
module_param_hw(dma2, int, dma, 0444);
MODULE_PARM_DESC(dma2, "2nd dma # for opti9xx driver.");
#endif
#define OPTi9XX_HW_82C928 …
#define OPTi9XX_HW_82C929 …
#define OPTi9XX_HW_82C924 …
#define OPTi9XX_HW_82C925 …
#define OPTi9XX_HW_82C930 …
#define OPTi9XX_HW_82C931 …
#define OPTi9XX_HW_82C933 …
#define OPTi9XX_HW_LAST …
#define OPTi9XX_MC_REG(n) …
#ifdef OPTi93X
#define OPTi93X_STATUS …
#define OPTi93X_PORT …
#define OPTi93X_IRQ_PLAYBACK …
#define OPTi93X_IRQ_CAPTURE …
#endif
struct snd_opti9xx { … };
static int snd_opti9xx_pnp_is_probed;
#ifdef CONFIG_PNP
static const struct pnp_card_device_id snd_opti9xx_pnpids[] = …;
MODULE_DEVICE_TABLE(pnp_card, snd_opti9xx_pnpids);
#endif
#define DEV_NAME …
static const char * const snd_opti9xx_names[] = …;
static int snd_opti9xx_init(struct snd_opti9xx *chip,
unsigned short hardware)
{ … }
static unsigned char snd_opti9xx_read(struct snd_opti9xx *chip,
unsigned char reg)
{ … }
static void snd_opti9xx_write(struct snd_opti9xx *chip, unsigned char reg,
unsigned char value)
{ … }
static inline void snd_opti9xx_write_mask(struct snd_opti9xx *chip,
unsigned char reg, unsigned char value, unsigned char mask)
{ … }
static int snd_opti9xx_configure(struct snd_opti9xx *chip,
long port,
int irq, int dma1, int dma2,
long mpu_port, int mpu_irq)
{ … }
#ifdef OPTi93X
static const DECLARE_TLV_DB_SCALE(db_scale_5bit_3db_step, -9300, 300, 0);
static const DECLARE_TLV_DB_SCALE(db_scale_5bit, -4650, 150, 0);
static const DECLARE_TLV_DB_SCALE(db_scale_4bit_12db_max, -3300, 300, 0);
static const struct snd_kcontrol_new snd_opti93x_controls[] = {
WSS_DOUBLE("Master Playback Switch", 0,
OPTi93X_OUT_LEFT, OPTi93X_OUT_RIGHT, 7, 7, 1, 1),
WSS_DOUBLE_TLV("Master Playback Volume", 0,
OPTi93X_OUT_LEFT, OPTi93X_OUT_RIGHT, 1, 1, 31, 1,
db_scale_5bit_3db_step),
WSS_DOUBLE_TLV("PCM Playback Volume", 0,
CS4231_LEFT_OUTPUT, CS4231_RIGHT_OUTPUT, 0, 0, 31, 1,
db_scale_5bit),
WSS_DOUBLE_TLV("FM Playback Volume", 0,
CS4231_AUX2_LEFT_INPUT, CS4231_AUX2_RIGHT_INPUT, 1, 1, 15, 1,
db_scale_4bit_12db_max),
WSS_DOUBLE("Line Playback Switch", 0,
CS4231_LEFT_LINE_IN, CS4231_RIGHT_LINE_IN, 7, 7, 1, 1),
WSS_DOUBLE_TLV("Line Playback Volume", 0,
CS4231_LEFT_LINE_IN, CS4231_RIGHT_LINE_IN, 0, 0, 15, 1,
db_scale_4bit_12db_max),
WSS_DOUBLE("Mic Playback Switch", 0,
OPTi93X_MIC_LEFT_INPUT, OPTi93X_MIC_RIGHT_INPUT, 7, 7, 1, 1),
WSS_DOUBLE_TLV("Mic Playback Volume", 0,
OPTi93X_MIC_LEFT_INPUT, OPTi93X_MIC_RIGHT_INPUT, 1, 1, 15, 1,
db_scale_4bit_12db_max),
WSS_DOUBLE_TLV("CD Playback Volume", 0,
CS4231_AUX1_LEFT_INPUT, CS4231_AUX1_RIGHT_INPUT, 1, 1, 15, 1,
db_scale_4bit_12db_max),
WSS_DOUBLE("Aux Playback Switch", 0,
OPTi931_AUX_LEFT_INPUT, OPTi931_AUX_RIGHT_INPUT, 7, 7, 1, 1),
WSS_DOUBLE_TLV("Aux Playback Volume", 0,
OPTi931_AUX_LEFT_INPUT, OPTi931_AUX_RIGHT_INPUT, 1, 1, 15, 1,
db_scale_4bit_12db_max),
};
static int snd_opti93x_mixer(struct snd_wss *chip)
{
struct snd_card *card;
unsigned int idx;
struct snd_ctl_elem_id id1, id2;
int err;
if (snd_BUG_ON(!chip || !chip->pcm))
return -EINVAL;
card = chip->card;
strcpy(card->mixername, chip->pcm->name);
memset(&id1, 0, sizeof(id1));
memset(&id2, 0, sizeof(id2));
id1.iface = id2.iface = SNDRV_CTL_ELEM_IFACE_MIXER;
strcpy(id1.name, "Aux Playback Switch");
strcpy(id2.name, "CD Playback Switch");
err = snd_ctl_rename_id(card, &id1, &id2);
if (err < 0) {
snd_printk(KERN_ERR "Cannot rename opti93x control\n");
return err;
}
strcpy(id1.name, "Aux Playback Switch"); id1.index = 1;
strcpy(id2.name, "FM Playback Switch");
err = snd_ctl_rename_id(card, &id1, &id2);
if (err < 0) {
snd_printk(KERN_ERR "Cannot rename opti93x control\n");
return err;
}
strcpy(id1.name, "Aux Playback Volume"); id1.index = 1;
snd_ctl_remove_id(card, &id1);
id1.index = 0;
for (idx = 0; idx < ARRAY_SIZE(snd_opti93x_controls); idx++) {
strcpy(id1.name, snd_opti93x_controls[idx].name);
snd_ctl_remove_id(card, &id1);
err = snd_ctl_add(card,
snd_ctl_new1(&snd_opti93x_controls[idx], chip));
if (err < 0)
return err;
}
return 0;
}
static irqreturn_t snd_opti93x_interrupt(int irq, void *dev_id)
{
struct snd_opti9xx *chip = dev_id;
struct snd_wss *codec = chip->codec;
unsigned char status;
if (!codec)
return IRQ_HANDLED;
status = snd_opti9xx_read(chip, OPTi9XX_MC_REG(11));
if ((status & OPTi93X_IRQ_PLAYBACK) && codec->playback_substream)
snd_pcm_period_elapsed(codec->playback_substream);
if ((status & OPTi93X_IRQ_CAPTURE) && codec->capture_substream) {
snd_wss_overrange(codec);
snd_pcm_period_elapsed(codec->capture_substream);
}
outb(0x00, OPTi93X_PORT(codec, STATUS));
return IRQ_HANDLED;
}
#endif
static int snd_opti9xx_read_check(struct snd_card *card,
struct snd_opti9xx *chip)
{ … }
static int snd_card_opti9xx_detect(struct snd_card *card,
struct snd_opti9xx *chip)
{ … }
#ifdef CONFIG_PNP
static int snd_card_opti9xx_pnp(struct snd_opti9xx *chip,
struct pnp_card_link *card,
const struct pnp_card_device_id *pid)
{ … }
#endif
static int snd_opti9xx_probe(struct snd_card *card)
{ … }
static int snd_opti9xx_card_new(struct device *pdev, struct snd_card **cardp)
{ … }
static int snd_opti9xx_isa_match(struct device *devptr,
unsigned int dev)
{ … }
static int snd_opti9xx_isa_probe(struct device *devptr,
unsigned int dev)
{ … }
#ifdef CONFIG_PM
static int snd_opti9xx_suspend(struct snd_card *card)
{ … }
static int snd_opti9xx_resume(struct snd_card *card)
{ … }
static int snd_opti9xx_isa_suspend(struct device *dev, unsigned int n,
pm_message_t state)
{ … }
static int snd_opti9xx_isa_resume(struct device *dev, unsigned int n)
{ … }
#endif
static struct isa_driver snd_opti9xx_driver = …;
#ifdef CONFIG_PNP
static int snd_opti9xx_pnp_probe(struct pnp_card_link *pcard,
const struct pnp_card_device_id *pid)
{ … }
static void snd_opti9xx_pnp_remove(struct pnp_card_link *pcard)
{ … }
#ifdef CONFIG_PM
static int snd_opti9xx_pnp_suspend(struct pnp_card_link *pcard,
pm_message_t state)
{ … }
static int snd_opti9xx_pnp_resume(struct pnp_card_link *pcard)
{ … }
#endif
static struct pnp_card_driver opti9xx_pnpc_driver = …;
#endif
#ifdef OPTi93X
#define CHIP_NAME …
#else
#define CHIP_NAME …
#endif
static int __init alsa_card_opti9xx_init(void)
{ … }
static void __exit alsa_card_opti9xx_exit(void)
{ … }
module_init(…) …
module_exit(…)