2005-04-17 02:20:36 +04:00
|
|
|
/*
|
|
|
|
* Driver for AMD InterWave soundcard
|
2007-10-15 11:50:19 +04:00
|
|
|
* Copyright (c) by Jaroslav Kysela <perex@perex.cz>
|
2005-04-17 02:20:36 +04:00
|
|
|
*
|
|
|
|
*
|
|
|
|
* This program is free software; you can redistribute it and/or modify
|
|
|
|
* it under the terms of the GNU General Public License as published by
|
|
|
|
* the Free Software Foundation; either version 2 of the License, or
|
|
|
|
* (at your option) any later version.
|
|
|
|
*
|
|
|
|
* This program is distributed in the hope that it will be useful,
|
|
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
* GNU General Public License for more details.
|
|
|
|
*
|
|
|
|
* You should have received a copy of the GNU General Public License
|
|
|
|
* along with this program; if not, write to the Free Software
|
|
|
|
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
|
|
|
*
|
|
|
|
* 1999/07/22 Erik Inge Bolso <knan@mo.himolde.no>
|
|
|
|
* * mixer group handlers
|
|
|
|
*
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include <linux/init.h>
|
2005-11-17 19:13:43 +03:00
|
|
|
#include <linux/err.h>
|
2007-02-22 14:50:54 +03:00
|
|
|
#include <linux/isa.h>
|
2005-11-17 19:13:43 +03:00
|
|
|
#include <linux/delay.h>
|
2005-04-17 02:20:36 +04:00
|
|
|
#include <linux/pnp.h>
|
|
|
|
#include <linux/moduleparam.h>
|
2005-11-17 19:13:43 +03:00
|
|
|
#include <asm/dma.h>
|
2005-04-17 02:20:36 +04:00
|
|
|
#include <sound/core.h>
|
|
|
|
#include <sound/gus.h>
|
2008-07-31 23:02:42 +04:00
|
|
|
#include <sound/wss.h>
|
2005-04-17 02:20:36 +04:00
|
|
|
#ifdef SNDRV_STB
|
|
|
|
#include <sound/tea6330t.h>
|
|
|
|
#endif
|
|
|
|
#define SNDRV_LEGACY_FIND_FREE_IRQ
|
|
|
|
#define SNDRV_LEGACY_FIND_FREE_DMA
|
|
|
|
#include <sound/initval.h>
|
|
|
|
|
2007-10-15 11:50:19 +04:00
|
|
|
MODULE_AUTHOR("Jaroslav Kysela <perex@perex.cz>");
|
2005-04-17 02:20:36 +04:00
|
|
|
MODULE_LICENSE("GPL");
|
|
|
|
#ifndef SNDRV_STB
|
|
|
|
MODULE_DESCRIPTION("AMD InterWave");
|
|
|
|
MODULE_SUPPORTED_DEVICE("{{Gravis,UltraSound Plug & Play},"
|
|
|
|
"{STB,SoundRage32},"
|
|
|
|
"{MED,MED3210},"
|
|
|
|
"{Dynasonix,Dynasonix Pro},"
|
|
|
|
"{Panasonic,PCA761AW}}");
|
|
|
|
#else
|
|
|
|
MODULE_DESCRIPTION("AMD InterWave STB with TEA6330T");
|
|
|
|
MODULE_SUPPORTED_DEVICE("{{AMD,InterWave STB with TEA6330T}}");
|
|
|
|
#endif
|
|
|
|
|
|
|
|
static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX; /* Index 0-MAX */
|
|
|
|
static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR; /* ID for this card */
|
|
|
|
static int enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE_ISAPNP; /* Enable this card */
|
|
|
|
#ifdef CONFIG_PNP
|
|
|
|
static int isapnp[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS - 1)] = 1};
|
|
|
|
#endif
|
|
|
|
static long port[SNDRV_CARDS] = SNDRV_DEFAULT_PORT; /* 0x210,0x220,0x230,0x240,0x250,0x260 */
|
|
|
|
#ifdef SNDRV_STB
|
|
|
|
static long port_tc[SNDRV_CARDS] = SNDRV_DEFAULT_PORT; /* 0x350,0x360,0x370,0x380 */
|
|
|
|
#endif
|
|
|
|
static int irq[SNDRV_CARDS] = SNDRV_DEFAULT_IRQ; /* 2,3,5,9,11,12,15 */
|
|
|
|
static int dma1[SNDRV_CARDS] = SNDRV_DEFAULT_DMA; /* 0,1,3,5,6,7 */
|
|
|
|
static int dma2[SNDRV_CARDS] = SNDRV_DEFAULT_DMA; /* 0,1,3,5,6,7 */
|
|
|
|
static int joystick_dac[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS - 1)] = 29};
|
|
|
|
/* 0 to 31, (0.59V-4.52V or 0.389V-2.98V) */
|
2006-05-17 19:14:51 +04:00
|
|
|
static int midi[SNDRV_CARDS];
|
2005-04-17 02:20:36 +04:00
|
|
|
static int pcm_channels[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS - 1)] = 2};
|
2006-05-17 19:14:51 +04:00
|
|
|
static int effect[SNDRV_CARDS];
|
2005-04-17 02:20:36 +04:00
|
|
|
|
[ALSA] Add snd_card_set_generic_dev() call to ISA drivers
ISA,CMI8330 driver,ES18xx driver,OPL3SA2 driver,Sound Galaxy driver
Sound Scape driver,AD1848 driver,CS4231 driver,CS4236+ driver
ES1688 driver,GUS Classic driver,GUS Extreme driver,GUS MAX driver
AMD InterWave driver,Opti9xx drivers,SB16/AWE driver,SB8 driver
Wavefront drivers
- Added snd_card_set_generic_dev() call.
- Added SND_GENERIC_DRIVER to Kconfig.
- Clean up the error path in probe if necessary.
Signed-off-by: Takashi Iwai <tiwai@suse.de>
2005-09-05 19:19:20 +04:00
|
|
|
#ifdef SNDRV_STB
|
|
|
|
#define PFX "interwave-stb: "
|
2005-11-17 19:13:43 +03:00
|
|
|
#define INTERWAVE_DRIVER "snd_interwave_stb"
|
|
|
|
#define INTERWAVE_PNP_DRIVER "interwave-stb"
|
[ALSA] Add snd_card_set_generic_dev() call to ISA drivers
ISA,CMI8330 driver,ES18xx driver,OPL3SA2 driver,Sound Galaxy driver
Sound Scape driver,AD1848 driver,CS4231 driver,CS4236+ driver
ES1688 driver,GUS Classic driver,GUS Extreme driver,GUS MAX driver
AMD InterWave driver,Opti9xx drivers,SB16/AWE driver,SB8 driver
Wavefront drivers
- Added snd_card_set_generic_dev() call.
- Added SND_GENERIC_DRIVER to Kconfig.
- Clean up the error path in probe if necessary.
Signed-off-by: Takashi Iwai <tiwai@suse.de>
2005-09-05 19:19:20 +04:00
|
|
|
#else
|
|
|
|
#define PFX "interwave: "
|
2005-11-17 19:13:43 +03:00
|
|
|
#define INTERWAVE_DRIVER "snd_interwave"
|
|
|
|
#define INTERWAVE_PNP_DRIVER "interwave"
|
[ALSA] Add snd_card_set_generic_dev() call to ISA drivers
ISA,CMI8330 driver,ES18xx driver,OPL3SA2 driver,Sound Galaxy driver
Sound Scape driver,AD1848 driver,CS4231 driver,CS4236+ driver
ES1688 driver,GUS Classic driver,GUS Extreme driver,GUS MAX driver
AMD InterWave driver,Opti9xx drivers,SB16/AWE driver,SB8 driver
Wavefront drivers
- Added snd_card_set_generic_dev() call.
- Added SND_GENERIC_DRIVER to Kconfig.
- Clean up the error path in probe if necessary.
Signed-off-by: Takashi Iwai <tiwai@suse.de>
2005-09-05 19:19:20 +04:00
|
|
|
#endif
|
|
|
|
|
2005-04-17 02:20:36 +04:00
|
|
|
module_param_array(index, int, NULL, 0444);
|
|
|
|
MODULE_PARM_DESC(index, "Index value for InterWave soundcard.");
|
|
|
|
module_param_array(id, charp, NULL, 0444);
|
|
|
|
MODULE_PARM_DESC(id, "ID string for InterWave soundcard.");
|
|
|
|
module_param_array(enable, bool, NULL, 0444);
|
|
|
|
MODULE_PARM_DESC(enable, "Enable InterWave soundcard.");
|
|
|
|
#ifdef CONFIG_PNP
|
|
|
|
module_param_array(isapnp, bool, NULL, 0444);
|
|
|
|
MODULE_PARM_DESC(isapnp, "ISA PnP detection for specified soundcard.");
|
|
|
|
#endif
|
|
|
|
module_param_array(port, long, NULL, 0444);
|
|
|
|
MODULE_PARM_DESC(port, "Port # for InterWave driver.");
|
|
|
|
#ifdef SNDRV_STB
|
|
|
|
module_param_array(port_tc, long, NULL, 0444);
|
|
|
|
MODULE_PARM_DESC(port_tc, "Tone control (TEA6330T - i2c bus) port # for InterWave driver.");
|
|
|
|
#endif
|
|
|
|
module_param_array(irq, int, NULL, 0444);
|
|
|
|
MODULE_PARM_DESC(irq, "IRQ # for InterWave driver.");
|
|
|
|
module_param_array(dma1, int, NULL, 0444);
|
|
|
|
MODULE_PARM_DESC(dma1, "DMA1 # for InterWave driver.");
|
|
|
|
module_param_array(dma2, int, NULL, 0444);
|
|
|
|
MODULE_PARM_DESC(dma2, "DMA2 # for InterWave driver.");
|
|
|
|
module_param_array(joystick_dac, int, NULL, 0444);
|
|
|
|
MODULE_PARM_DESC(joystick_dac, "Joystick DAC level 0.59V-4.52V or 0.389V-2.98V for InterWave driver.");
|
|
|
|
module_param_array(midi, int, NULL, 0444);
|
|
|
|
MODULE_PARM_DESC(midi, "MIDI UART enable for InterWave driver.");
|
|
|
|
module_param_array(pcm_channels, int, NULL, 0444);
|
|
|
|
MODULE_PARM_DESC(pcm_channels, "Reserved PCM channels for InterWave driver.");
|
|
|
|
module_param_array(effect, int, NULL, 0444);
|
|
|
|
MODULE_PARM_DESC(effect, "Effects enable for InterWave driver.");
|
|
|
|
|
|
|
|
struct snd_interwave {
|
|
|
|
int irq;
|
2005-11-17 16:36:44 +03:00
|
|
|
struct snd_card *card;
|
|
|
|
struct snd_gus_card *gus;
|
2008-07-31 23:03:41 +04:00
|
|
|
struct snd_wss *wss;
|
2005-04-17 02:20:36 +04:00
|
|
|
#ifdef SNDRV_STB
|
|
|
|
struct resource *i2c_res;
|
|
|
|
#endif
|
|
|
|
unsigned short gus_status_reg;
|
|
|
|
unsigned short pcm_status_reg;
|
|
|
|
#ifdef CONFIG_PNP
|
|
|
|
struct pnp_dev *dev;
|
|
|
|
#ifdef SNDRV_STB
|
|
|
|
struct pnp_dev *devtc;
|
|
|
|
#endif
|
|
|
|
#endif
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
#ifdef CONFIG_PNP
|
2007-05-15 13:42:56 +04:00
|
|
|
static int isa_registered;
|
2007-02-22 14:50:54 +03:00
|
|
|
static int pnp_registered;
|
2005-04-17 02:20:36 +04:00
|
|
|
|
|
|
|
static struct pnp_card_device_id snd_interwave_pnpids[] = {
|
|
|
|
#ifndef SNDRV_STB
|
|
|
|
/* Gravis UltraSound Plug & Play */
|
|
|
|
{ .id = "GRV0001", .devs = { { .id = "GRV0000" } } },
|
|
|
|
/* STB SoundRage32 */
|
|
|
|
{ .id = "STB011a", .devs = { { .id = "STB0010" } } },
|
|
|
|
/* MED3210 */
|
|
|
|
{ .id = "DXP3201", .devs = { { .id = "DXP0010" } } },
|
|
|
|
/* Dynasonic Pro */
|
|
|
|
/* This device also have CDC1117:DynaSonix Pro Audio Effects Processor */
|
|
|
|
{ .id = "CDC1111", .devs = { { .id = "CDC1112" } } },
|
|
|
|
/* Panasonic PCA761AW Audio Card */
|
|
|
|
{ .id = "ADV55ff", .devs = { { .id = "ADV0010" } } },
|
|
|
|
/* InterWave STB without TEA6330T */
|
|
|
|
{ .id = "ADV550a", .devs = { { .id = "ADV0010" } } },
|
|
|
|
#else
|
|
|
|
/* InterWave STB with TEA6330T */
|
|
|
|
{ .id = "ADV550a", .devs = { { .id = "ADV0010" }, { .id = "ADV0015" } } },
|
|
|
|
#endif
|
|
|
|
{ .id = "" }
|
|
|
|
};
|
|
|
|
|
|
|
|
MODULE_DEVICE_TABLE(pnp_card, snd_interwave_pnpids);
|
|
|
|
|
|
|
|
#endif /* CONFIG_PNP */
|
|
|
|
|
|
|
|
|
|
|
|
#ifdef SNDRV_STB
|
2005-11-17 16:36:44 +03:00
|
|
|
static void snd_interwave_i2c_setlines(struct snd_i2c_bus *bus, int ctrl, int data)
|
2005-04-17 02:20:36 +04:00
|
|
|
{
|
|
|
|
unsigned long port = bus->private_value;
|
|
|
|
|
|
|
|
#if 0
|
2009-02-05 17:46:48 +03:00
|
|
|
printk(KERN_DEBUG "i2c_setlines - 0x%lx <- %i,%i\n", port, ctrl, data);
|
2005-04-17 02:20:36 +04:00
|
|
|
#endif
|
|
|
|
outb((data << 1) | ctrl, port);
|
|
|
|
udelay(10);
|
|
|
|
}
|
|
|
|
|
2005-11-17 16:36:44 +03:00
|
|
|
static int snd_interwave_i2c_getclockline(struct snd_i2c_bus *bus)
|
2005-04-17 02:20:36 +04:00
|
|
|
{
|
|
|
|
unsigned long port = bus->private_value;
|
|
|
|
unsigned char res;
|
|
|
|
|
|
|
|
res = inb(port) & 1;
|
|
|
|
#if 0
|
2009-02-05 17:46:48 +03:00
|
|
|
printk(KERN_DEBUG "i2c_getclockline - 0x%lx -> %i\n", port, res);
|
2005-04-17 02:20:36 +04:00
|
|
|
#endif
|
|
|
|
return res;
|
|
|
|
}
|
|
|
|
|
2005-11-17 16:36:44 +03:00
|
|
|
static int snd_interwave_i2c_getdataline(struct snd_i2c_bus *bus, int ack)
|
2005-04-17 02:20:36 +04:00
|
|
|
{
|
|
|
|
unsigned long port = bus->private_value;
|
|
|
|
unsigned char res;
|
|
|
|
|
|
|
|
if (ack)
|
|
|
|
udelay(10);
|
|
|
|
res = (inb(port) & 2) >> 1;
|
|
|
|
#if 0
|
2009-02-05 17:46:48 +03:00
|
|
|
printk(KERN_DEBUG "i2c_getdataline - 0x%lx -> %i\n", port, res);
|
2005-04-17 02:20:36 +04:00
|
|
|
#endif
|
|
|
|
return res;
|
|
|
|
}
|
|
|
|
|
2005-11-17 16:36:44 +03:00
|
|
|
static struct snd_i2c_bit_ops snd_interwave_i2c_bit_ops = {
|
2005-04-17 02:20:36 +04:00
|
|
|
.setlines = snd_interwave_i2c_setlines,
|
|
|
|
.getclock = snd_interwave_i2c_getclockline,
|
|
|
|
.getdata = snd_interwave_i2c_getdataline,
|
|
|
|
};
|
|
|
|
|
|
|
|
static int __devinit snd_interwave_detect_stb(struct snd_interwave *iwcard,
|
2005-11-17 16:36:44 +03:00
|
|
|
struct snd_gus_card * gus, int dev,
|
|
|
|
struct snd_i2c_bus **rbus)
|
2005-04-17 02:20:36 +04:00
|
|
|
{
|
|
|
|
unsigned long port;
|
2005-11-17 16:36:44 +03:00
|
|
|
struct snd_i2c_bus *bus;
|
|
|
|
struct snd_card *card = iwcard->card;
|
2005-04-17 02:20:36 +04:00
|
|
|
char name[32];
|
|
|
|
int err;
|
|
|
|
|
|
|
|
*rbus = NULL;
|
|
|
|
port = port_tc[dev];
|
|
|
|
if (port == SNDRV_AUTO_PORT) {
|
|
|
|
port = 0x350;
|
|
|
|
if (gus->gf1.port == 0x250) {
|
|
|
|
port = 0x360;
|
|
|
|
}
|
|
|
|
while (port <= 0x380) {
|
|
|
|
if ((iwcard->i2c_res = request_region(port, 1, "InterWave (I2C bus)")) != NULL)
|
|
|
|
break;
|
|
|
|
port += 0x10;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
iwcard->i2c_res = request_region(port, 1, "InterWave (I2C bus)");
|
|
|
|
}
|
|
|
|
if (iwcard->i2c_res == NULL) {
|
|
|
|
snd_printk(KERN_ERR "interwave: can't grab i2c bus port\n");
|
|
|
|
return -ENODEV;
|
|
|
|
}
|
|
|
|
|
|
|
|
sprintf(name, "InterWave-%i", card->number);
|
|
|
|
if ((err = snd_i2c_bus_create(card, name, NULL, &bus)) < 0)
|
|
|
|
return err;
|
|
|
|
bus->private_value = port;
|
|
|
|
bus->hw_ops.bit = &snd_interwave_i2c_bit_ops;
|
|
|
|
if ((err = snd_tea6330t_detect(bus, 0)) < 0)
|
|
|
|
return err;
|
|
|
|
*rbus = bus;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
static int __devinit snd_interwave_detect(struct snd_interwave *iwcard,
|
2005-11-17 16:36:44 +03:00
|
|
|
struct snd_gus_card * gus,
|
2005-04-17 02:20:36 +04:00
|
|
|
int dev
|
|
|
|
#ifdef SNDRV_STB
|
2005-11-17 16:36:44 +03:00
|
|
|
, struct snd_i2c_bus **rbus
|
2005-04-17 02:20:36 +04:00
|
|
|
#endif
|
|
|
|
)
|
|
|
|
{
|
|
|
|
unsigned long flags;
|
|
|
|
unsigned char rev1, rev2;
|
[ALSA] Add snd_card_set_generic_dev() call to ISA drivers
ISA,CMI8330 driver,ES18xx driver,OPL3SA2 driver,Sound Galaxy driver
Sound Scape driver,AD1848 driver,CS4231 driver,CS4236+ driver
ES1688 driver,GUS Classic driver,GUS Extreme driver,GUS MAX driver
AMD InterWave driver,Opti9xx drivers,SB16/AWE driver,SB8 driver
Wavefront drivers
- Added snd_card_set_generic_dev() call.
- Added SND_GENERIC_DRIVER to Kconfig.
- Clean up the error path in probe if necessary.
Signed-off-by: Takashi Iwai <tiwai@suse.de>
2005-09-05 19:19:20 +04:00
|
|
|
int d;
|
2005-04-17 02:20:36 +04:00
|
|
|
|
|
|
|
snd_gf1_i_write8(gus, SNDRV_GF1_GB_RESET, 0); /* reset GF1 */
|
[ALSA] Add snd_card_set_generic_dev() call to ISA drivers
ISA,CMI8330 driver,ES18xx driver,OPL3SA2 driver,Sound Galaxy driver
Sound Scape driver,AD1848 driver,CS4231 driver,CS4236+ driver
ES1688 driver,GUS Classic driver,GUS Extreme driver,GUS MAX driver
AMD InterWave driver,Opti9xx drivers,SB16/AWE driver,SB8 driver
Wavefront drivers
- Added snd_card_set_generic_dev() call.
- Added SND_GENERIC_DRIVER to Kconfig.
- Clean up the error path in probe if necessary.
Signed-off-by: Takashi Iwai <tiwai@suse.de>
2005-09-05 19:19:20 +04:00
|
|
|
if (((d = snd_gf1_i_look8(gus, SNDRV_GF1_GB_RESET)) & 0x07) != 0) {
|
|
|
|
snd_printdd("[0x%lx] check 1 failed - 0x%x\n", gus->gf1.port, d);
|
2005-04-17 02:20:36 +04:00
|
|
|
return -ENODEV;
|
[ALSA] Add snd_card_set_generic_dev() call to ISA drivers
ISA,CMI8330 driver,ES18xx driver,OPL3SA2 driver,Sound Galaxy driver
Sound Scape driver,AD1848 driver,CS4231 driver,CS4236+ driver
ES1688 driver,GUS Classic driver,GUS Extreme driver,GUS MAX driver
AMD InterWave driver,Opti9xx drivers,SB16/AWE driver,SB8 driver
Wavefront drivers
- Added snd_card_set_generic_dev() call.
- Added SND_GENERIC_DRIVER to Kconfig.
- Clean up the error path in probe if necessary.
Signed-off-by: Takashi Iwai <tiwai@suse.de>
2005-09-05 19:19:20 +04:00
|
|
|
}
|
2005-04-17 02:20:36 +04:00
|
|
|
udelay(160);
|
|
|
|
snd_gf1_i_write8(gus, SNDRV_GF1_GB_RESET, 1); /* release reset */
|
|
|
|
udelay(160);
|
[ALSA] Add snd_card_set_generic_dev() call to ISA drivers
ISA,CMI8330 driver,ES18xx driver,OPL3SA2 driver,Sound Galaxy driver
Sound Scape driver,AD1848 driver,CS4231 driver,CS4236+ driver
ES1688 driver,GUS Classic driver,GUS Extreme driver,GUS MAX driver
AMD InterWave driver,Opti9xx drivers,SB16/AWE driver,SB8 driver
Wavefront drivers
- Added snd_card_set_generic_dev() call.
- Added SND_GENERIC_DRIVER to Kconfig.
- Clean up the error path in probe if necessary.
Signed-off-by: Takashi Iwai <tiwai@suse.de>
2005-09-05 19:19:20 +04:00
|
|
|
if (((d = snd_gf1_i_look8(gus, SNDRV_GF1_GB_RESET)) & 0x07) != 1) {
|
|
|
|
snd_printdd("[0x%lx] check 2 failed - 0x%x\n", gus->gf1.port, d);
|
2005-04-17 02:20:36 +04:00
|
|
|
return -ENODEV;
|
[ALSA] Add snd_card_set_generic_dev() call to ISA drivers
ISA,CMI8330 driver,ES18xx driver,OPL3SA2 driver,Sound Galaxy driver
Sound Scape driver,AD1848 driver,CS4231 driver,CS4236+ driver
ES1688 driver,GUS Classic driver,GUS Extreme driver,GUS MAX driver
AMD InterWave driver,Opti9xx drivers,SB16/AWE driver,SB8 driver
Wavefront drivers
- Added snd_card_set_generic_dev() call.
- Added SND_GENERIC_DRIVER to Kconfig.
- Clean up the error path in probe if necessary.
Signed-off-by: Takashi Iwai <tiwai@suse.de>
2005-09-05 19:19:20 +04:00
|
|
|
}
|
2005-04-17 02:20:36 +04:00
|
|
|
spin_lock_irqsave(&gus->reg_lock, flags);
|
|
|
|
rev1 = snd_gf1_look8(gus, SNDRV_GF1_GB_VERSION_NUMBER);
|
|
|
|
snd_gf1_write8(gus, SNDRV_GF1_GB_VERSION_NUMBER, ~rev1);
|
|
|
|
rev2 = snd_gf1_look8(gus, SNDRV_GF1_GB_VERSION_NUMBER);
|
|
|
|
snd_gf1_write8(gus, SNDRV_GF1_GB_VERSION_NUMBER, rev1);
|
|
|
|
spin_unlock_irqrestore(&gus->reg_lock, flags);
|
|
|
|
snd_printdd("[0x%lx] InterWave check - rev1=0x%x, rev2=0x%x\n", gus->gf1.port, rev1, rev2);
|
|
|
|
if ((rev1 & 0xf0) == (rev2 & 0xf0) &&
|
|
|
|
(rev1 & 0x0f) != (rev2 & 0x0f)) {
|
|
|
|
snd_printdd("[0x%lx] InterWave check - passed\n", gus->gf1.port);
|
|
|
|
gus->interwave = 1;
|
|
|
|
strcpy(gus->card->shortname, "AMD InterWave");
|
|
|
|
gus->revision = rev1 >> 4;
|
|
|
|
#ifndef SNDRV_STB
|
|
|
|
return 0; /* ok.. We have an InterWave board */
|
|
|
|
#else
|
|
|
|
return snd_interwave_detect_stb(iwcard, gus, dev, rbus);
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
snd_printdd("[0x%lx] InterWave check - failed\n", gus->gf1.port);
|
|
|
|
return -ENODEV;
|
|
|
|
}
|
|
|
|
|
IRQ: Maintain regs pointer globally rather than passing to IRQ handlers
Maintain a per-CPU global "struct pt_regs *" variable which can be used instead
of passing regs around manually through all ~1800 interrupt handlers in the
Linux kernel.
The regs pointer is used in few places, but it potentially costs both stack
space and code to pass it around. On the FRV arch, removing the regs parameter
from all the genirq function results in a 20% speed up of the IRQ exit path
(ie: from leaving timer_interrupt() to leaving do_IRQ()).
Where appropriate, an arch may override the generic storage facility and do
something different with the variable. On FRV, for instance, the address is
maintained in GR28 at all times inside the kernel as part of general exception
handling.
Having looked over the code, it appears that the parameter may be handed down
through up to twenty or so layers of functions. Consider a USB character
device attached to a USB hub, attached to a USB controller that posts its
interrupts through a cascaded auxiliary interrupt controller. A character
device driver may want to pass regs to the sysrq handler through the input
layer which adds another few layers of parameter passing.
I've build this code with allyesconfig for x86_64 and i386. I've runtested the
main part of the code on FRV and i386, though I can't test most of the drivers.
I've also done partial conversion for powerpc and MIPS - these at least compile
with minimal configurations.
This will affect all archs. Mostly the changes should be relatively easy.
Take do_IRQ(), store the regs pointer at the beginning, saving the old one:
struct pt_regs *old_regs = set_irq_regs(regs);
And put the old one back at the end:
set_irq_regs(old_regs);
Don't pass regs through to generic_handle_irq() or __do_IRQ().
In timer_interrupt(), this sort of change will be necessary:
- update_process_times(user_mode(regs));
- profile_tick(CPU_PROFILING, regs);
+ update_process_times(user_mode(get_irq_regs()));
+ profile_tick(CPU_PROFILING);
I'd like to move update_process_times()'s use of get_irq_regs() into itself,
except that i386, alone of the archs, uses something other than user_mode().
Some notes on the interrupt handling in the drivers:
(*) input_dev() is now gone entirely. The regs pointer is no longer stored in
the input_dev struct.
(*) finish_unlinks() in drivers/usb/host/ohci-q.c needs checking. It does
something different depending on whether it's been supplied with a regs
pointer or not.
(*) Various IRQ handler function pointers have been moved to type
irq_handler_t.
Signed-Off-By: David Howells <dhowells@redhat.com>
(cherry picked from 1b16e7ac850969f38b375e511e3fa2f474a33867 commit)
2006-10-05 17:55:46 +04:00
|
|
|
static irqreturn_t snd_interwave_interrupt(int irq, void *dev_id)
|
2005-04-17 02:20:36 +04:00
|
|
|
{
|
2006-10-06 23:00:58 +04:00
|
|
|
struct snd_interwave *iwcard = dev_id;
|
2005-04-17 02:20:36 +04:00
|
|
|
int loop, max = 5;
|
|
|
|
int handled = 0;
|
|
|
|
|
|
|
|
do {
|
|
|
|
loop = 0;
|
|
|
|
if (inb(iwcard->gus_status_reg)) {
|
|
|
|
handled = 1;
|
IRQ: Maintain regs pointer globally rather than passing to IRQ handlers
Maintain a per-CPU global "struct pt_regs *" variable which can be used instead
of passing regs around manually through all ~1800 interrupt handlers in the
Linux kernel.
The regs pointer is used in few places, but it potentially costs both stack
space and code to pass it around. On the FRV arch, removing the regs parameter
from all the genirq function results in a 20% speed up of the IRQ exit path
(ie: from leaving timer_interrupt() to leaving do_IRQ()).
Where appropriate, an arch may override the generic storage facility and do
something different with the variable. On FRV, for instance, the address is
maintained in GR28 at all times inside the kernel as part of general exception
handling.
Having looked over the code, it appears that the parameter may be handed down
through up to twenty or so layers of functions. Consider a USB character
device attached to a USB hub, attached to a USB controller that posts its
interrupts through a cascaded auxiliary interrupt controller. A character
device driver may want to pass regs to the sysrq handler through the input
layer which adds another few layers of parameter passing.
I've build this code with allyesconfig for x86_64 and i386. I've runtested the
main part of the code on FRV and i386, though I can't test most of the drivers.
I've also done partial conversion for powerpc and MIPS - these at least compile
with minimal configurations.
This will affect all archs. Mostly the changes should be relatively easy.
Take do_IRQ(), store the regs pointer at the beginning, saving the old one:
struct pt_regs *old_regs = set_irq_regs(regs);
And put the old one back at the end:
set_irq_regs(old_regs);
Don't pass regs through to generic_handle_irq() or __do_IRQ().
In timer_interrupt(), this sort of change will be necessary:
- update_process_times(user_mode(regs));
- profile_tick(CPU_PROFILING, regs);
+ update_process_times(user_mode(get_irq_regs()));
+ profile_tick(CPU_PROFILING);
I'd like to move update_process_times()'s use of get_irq_regs() into itself,
except that i386, alone of the archs, uses something other than user_mode().
Some notes on the interrupt handling in the drivers:
(*) input_dev() is now gone entirely. The regs pointer is no longer stored in
the input_dev struct.
(*) finish_unlinks() in drivers/usb/host/ohci-q.c needs checking. It does
something different depending on whether it's been supplied with a regs
pointer or not.
(*) Various IRQ handler function pointers have been moved to type
irq_handler_t.
Signed-Off-By: David Howells <dhowells@redhat.com>
(cherry picked from 1b16e7ac850969f38b375e511e3fa2f474a33867 commit)
2006-10-05 17:55:46 +04:00
|
|
|
snd_gus_interrupt(irq, iwcard->gus);
|
2005-04-17 02:20:36 +04:00
|
|
|
loop++;
|
|
|
|
}
|
|
|
|
if (inb(iwcard->pcm_status_reg) & 0x01) { /* IRQ bit is set? */
|
|
|
|
handled = 1;
|
2008-07-31 23:03:41 +04:00
|
|
|
snd_wss_interrupt(irq, iwcard->wss);
|
2005-04-17 02:20:36 +04:00
|
|
|
loop++;
|
|
|
|
}
|
|
|
|
} while (loop && --max > 0);
|
|
|
|
return IRQ_RETVAL(handled);
|
|
|
|
}
|
|
|
|
|
2005-11-17 16:36:44 +03:00
|
|
|
static void __devinit snd_interwave_reset(struct snd_gus_card * gus)
|
2005-04-17 02:20:36 +04:00
|
|
|
{
|
|
|
|
snd_gf1_write8(gus, SNDRV_GF1_GB_RESET, 0x00);
|
|
|
|
udelay(160);
|
|
|
|
snd_gf1_write8(gus, SNDRV_GF1_GB_RESET, 0x01);
|
|
|
|
udelay(160);
|
|
|
|
}
|
|
|
|
|
2005-11-17 16:36:44 +03:00
|
|
|
static void __devinit snd_interwave_bank_sizes(struct snd_gus_card * gus, int *sizes)
|
2005-04-17 02:20:36 +04:00
|
|
|
{
|
|
|
|
unsigned int idx;
|
|
|
|
unsigned int local;
|
|
|
|
unsigned char d;
|
|
|
|
|
|
|
|
for (idx = 0; idx < 4; idx++) {
|
|
|
|
sizes[idx] = 0;
|
|
|
|
d = 0x55;
|
|
|
|
for (local = idx << 22;
|
|
|
|
local < (idx << 22) + 0x400000;
|
|
|
|
local += 0x40000, d++) {
|
|
|
|
snd_gf1_poke(gus, local, d);
|
|
|
|
snd_gf1_poke(gus, local + 1, d + 1);
|
|
|
|
#if 0
|
2009-02-05 17:46:48 +03:00
|
|
|
printk(KERN_DEBUG "d = 0x%x, local = 0x%x, "
|
|
|
|
"local + 1 = 0x%x, idx << 22 = 0x%x\n",
|
2005-04-17 02:20:36 +04:00
|
|
|
d,
|
|
|
|
snd_gf1_peek(gus, local),
|
|
|
|
snd_gf1_peek(gus, local + 1),
|
|
|
|
snd_gf1_peek(gus, idx << 22));
|
|
|
|
#endif
|
|
|
|
if (snd_gf1_peek(gus, local) != d ||
|
|
|
|
snd_gf1_peek(gus, local + 1) != d + 1 ||
|
|
|
|
snd_gf1_peek(gus, idx << 22) != 0x55)
|
|
|
|
break;
|
|
|
|
sizes[idx]++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
#if 0
|
2009-02-05 17:46:48 +03:00
|
|
|
printk(KERN_DEBUG "sizes: %i %i %i %i\n",
|
|
|
|
sizes[0], sizes[1], sizes[2], sizes[3]);
|
2005-04-17 02:20:36 +04:00
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
struct rom_hdr {
|
|
|
|
/* 000 */ unsigned char iwave[8];
|
|
|
|
/* 008 */ unsigned char rom_hdr_revision;
|
|
|
|
/* 009 */ unsigned char series_number;
|
|
|
|
/* 010 */ unsigned char series_name[16];
|
|
|
|
/* 026 */ unsigned char date[10];
|
|
|
|
/* 036 */ unsigned short vendor_revision_major;
|
|
|
|
/* 038 */ unsigned short vendor_revision_minor;
|
|
|
|
/* 040 */ unsigned int rom_size;
|
|
|
|
/* 044 */ unsigned char copyright[128];
|
|
|
|
/* 172 */ unsigned char vendor_name[64];
|
|
|
|
/* 236 */ unsigned char rom_description[128];
|
|
|
|
/* 364 */ unsigned char pad[147];
|
|
|
|
/* 511 */ unsigned char csum;
|
|
|
|
};
|
|
|
|
|
2005-11-17 16:36:44 +03:00
|
|
|
static void __devinit snd_interwave_detect_memory(struct snd_gus_card * gus)
|
2005-04-17 02:20:36 +04:00
|
|
|
{
|
|
|
|
static unsigned int lmc[13] =
|
|
|
|
{
|
|
|
|
0x00000001, 0x00000101, 0x01010101, 0x00000401,
|
|
|
|
0x04040401, 0x00040101, 0x04040101, 0x00000004,
|
|
|
|
0x00000404, 0x04040404, 0x00000010, 0x00001010,
|
|
|
|
0x10101010
|
|
|
|
};
|
|
|
|
|
|
|
|
int bank_pos, pages;
|
|
|
|
unsigned int i, lmct;
|
|
|
|
int psizes[4];
|
|
|
|
unsigned char iwave[8];
|
|
|
|
unsigned char csum;
|
|
|
|
|
|
|
|
snd_interwave_reset(gus);
|
|
|
|
snd_gf1_write8(gus, SNDRV_GF1_GB_GLOBAL_MODE, snd_gf1_read8(gus, SNDRV_GF1_GB_GLOBAL_MODE) | 0x01); /* enhanced mode */
|
|
|
|
snd_gf1_write8(gus, SNDRV_GF1_GB_MEMORY_CONTROL, 0x01); /* DRAM I/O cycles selected */
|
|
|
|
snd_gf1_write16(gus, SNDRV_GF1_GW_MEMORY_CONFIG, (snd_gf1_look16(gus, SNDRV_GF1_GW_MEMORY_CONFIG) & 0xff10) | 0x004c);
|
|
|
|
/* ok.. simple test of memory size */
|
|
|
|
pages = 0;
|
|
|
|
snd_gf1_poke(gus, 0, 0x55);
|
|
|
|
snd_gf1_poke(gus, 1, 0xaa);
|
|
|
|
#if 1
|
|
|
|
if (snd_gf1_peek(gus, 0) == 0x55 && snd_gf1_peek(gus, 1) == 0xaa)
|
|
|
|
#else
|
|
|
|
if (0) /* ok.. for testing of 0k RAM */
|
|
|
|
#endif
|
|
|
|
{
|
|
|
|
snd_interwave_bank_sizes(gus, psizes);
|
|
|
|
lmct = (psizes[3] << 24) | (psizes[2] << 16) |
|
|
|
|
(psizes[1] << 8) | psizes[0];
|
|
|
|
#if 0
|
2009-02-05 17:46:48 +03:00
|
|
|
printk(KERN_DEBUG "lmct = 0x%08x\n", lmct);
|
2005-04-17 02:20:36 +04:00
|
|
|
#endif
|
|
|
|
for (i = 0; i < ARRAY_SIZE(lmc); i++)
|
|
|
|
if (lmct == lmc[i]) {
|
|
|
|
#if 0
|
2009-02-05 17:46:48 +03:00
|
|
|
printk(KERN_DEBUG "found !!! %i\n", i);
|
2005-04-17 02:20:36 +04:00
|
|
|
#endif
|
|
|
|
snd_gf1_write16(gus, SNDRV_GF1_GW_MEMORY_CONFIG, (snd_gf1_look16(gus, SNDRV_GF1_GW_MEMORY_CONFIG) & 0xfff0) | i);
|
|
|
|
snd_interwave_bank_sizes(gus, psizes);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
if (i >= ARRAY_SIZE(lmc) && !gus->gf1.enh_mode)
|
|
|
|
snd_gf1_write16(gus, SNDRV_GF1_GW_MEMORY_CONFIG, (snd_gf1_look16(gus, SNDRV_GF1_GW_MEMORY_CONFIG) & 0xfff0) | 2);
|
|
|
|
for (i = 0; i < 4; i++) {
|
|
|
|
gus->gf1.mem_alloc.banks_8[i].address =
|
|
|
|
gus->gf1.mem_alloc.banks_16[i].address = i << 22;
|
|
|
|
gus->gf1.mem_alloc.banks_8[i].size =
|
|
|
|
gus->gf1.mem_alloc.banks_16[i].size = psizes[i] << 18;
|
|
|
|
pages += psizes[i];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
pages <<= 18;
|
|
|
|
gus->gf1.memory = pages;
|
|
|
|
|
|
|
|
snd_gf1_write8(gus, SNDRV_GF1_GB_MEMORY_CONTROL, 0x03); /* select ROM */
|
|
|
|
snd_gf1_write16(gus, SNDRV_GF1_GW_MEMORY_CONFIG, (snd_gf1_look16(gus, SNDRV_GF1_GW_MEMORY_CONFIG) & 0xff1f) | (4 << 5));
|
|
|
|
gus->gf1.rom_banks = 0;
|
|
|
|
gus->gf1.rom_memory = 0;
|
|
|
|
for (bank_pos = 0; bank_pos < 16L * 1024L * 1024L; bank_pos += 4L * 1024L * 1024L) {
|
|
|
|
for (i = 0; i < 8; ++i)
|
|
|
|
iwave[i] = snd_gf1_peek(gus, bank_pos + i);
|
|
|
|
#ifdef CONFIG_SND_DEBUG_ROM
|
2005-10-20 20:26:44 +04:00
|
|
|
printk(KERN_DEBUG "ROM at 0x%06x = %02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x\n", bank_pos,
|
2005-04-17 02:20:36 +04:00
|
|
|
iwave[0], iwave[1], iwave[2], iwave[3],
|
|
|
|
iwave[4], iwave[5], iwave[6], iwave[7]);
|
|
|
|
#endif
|
|
|
|
if (strncmp(iwave, "INTRWAVE", 8))
|
|
|
|
continue; /* first check */
|
|
|
|
csum = 0;
|
|
|
|
for (i = 0; i < sizeof(struct rom_hdr); i++)
|
|
|
|
csum += snd_gf1_peek(gus, bank_pos + i);
|
|
|
|
#ifdef CONFIG_SND_DEBUG_ROM
|
2005-10-20 20:26:44 +04:00
|
|
|
printk(KERN_DEBUG "ROM checksum = 0x%x (computed)\n", csum);
|
2005-04-17 02:20:36 +04:00
|
|
|
#endif
|
|
|
|
if (csum != 0)
|
|
|
|
continue; /* not valid rom */
|
|
|
|
gus->gf1.rom_banks++;
|
|
|
|
gus->gf1.rom_present |= 1 << (bank_pos >> 22);
|
|
|
|
gus->gf1.rom_memory = snd_gf1_peek(gus, bank_pos + 40) |
|
|
|
|
(snd_gf1_peek(gus, bank_pos + 41) << 8) |
|
|
|
|
(snd_gf1_peek(gus, bank_pos + 42) << 16) |
|
|
|
|
(snd_gf1_peek(gus, bank_pos + 43) << 24);
|
|
|
|
}
|
|
|
|
#if 0
|
|
|
|
if (gus->gf1.rom_memory > 0) {
|
|
|
|
if (gus->gf1.rom_banks == 1 && gus->gf1.rom_present == 8)
|
|
|
|
gus->card->type = SNDRV_CARD_TYPE_IW_DYNASONIC;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
snd_gf1_write8(gus, SNDRV_GF1_GB_MEMORY_CONTROL, 0x00); /* select RAM */
|
|
|
|
|
|
|
|
if (!gus->gf1.enh_mode)
|
|
|
|
snd_interwave_reset(gus);
|
|
|
|
}
|
|
|
|
|
2005-11-17 16:36:44 +03:00
|
|
|
static void __devinit snd_interwave_init(int dev, struct snd_gus_card * gus)
|
2005-04-17 02:20:36 +04:00
|
|
|
{
|
|
|
|
unsigned long flags;
|
|
|
|
|
|
|
|
/* ok.. some InterWave specific initialization */
|
|
|
|
spin_lock_irqsave(&gus->reg_lock, flags);
|
|
|
|
snd_gf1_write8(gus, SNDRV_GF1_GB_SOUND_BLASTER_CONTROL, 0x00);
|
|
|
|
snd_gf1_write8(gus, SNDRV_GF1_GB_COMPATIBILITY, 0x1f);
|
|
|
|
snd_gf1_write8(gus, SNDRV_GF1_GB_DECODE_CONTROL, 0x49);
|
|
|
|
snd_gf1_write8(gus, SNDRV_GF1_GB_VERSION_NUMBER, 0x11);
|
|
|
|
snd_gf1_write8(gus, SNDRV_GF1_GB_MPU401_CONTROL_A, 0x00);
|
|
|
|
snd_gf1_write8(gus, SNDRV_GF1_GB_MPU401_CONTROL_B, 0x30);
|
|
|
|
snd_gf1_write8(gus, SNDRV_GF1_GB_EMULATION_IRQ, 0x00);
|
|
|
|
spin_unlock_irqrestore(&gus->reg_lock, flags);
|
|
|
|
gus->equal_irq = 1;
|
|
|
|
gus->codec_flag = 1;
|
|
|
|
gus->interwave = 1;
|
|
|
|
gus->max_flag = 1;
|
|
|
|
gus->joystick_dac = joystick_dac[dev];
|
|
|
|
|
|
|
|
}
|
|
|
|
|
2005-11-17 16:36:44 +03:00
|
|
|
static struct snd_kcontrol_new snd_interwave_controls[] = {
|
2008-07-31 23:03:41 +04:00
|
|
|
WSS_DOUBLE("Master Playback Switch", 0,
|
|
|
|
CS4231_LINE_LEFT_OUTPUT, CS4231_LINE_RIGHT_OUTPUT, 7, 7, 1, 1),
|
|
|
|
WSS_DOUBLE("Master Playback Volume", 0,
|
|
|
|
CS4231_LINE_LEFT_OUTPUT, CS4231_LINE_RIGHT_OUTPUT, 0, 0, 31, 1),
|
|
|
|
WSS_DOUBLE("Mic Playback Switch", 0,
|
|
|
|
CS4231_LEFT_MIC_INPUT, CS4231_RIGHT_MIC_INPUT, 7, 7, 1, 1),
|
|
|
|
WSS_DOUBLE("Mic Playback Volume", 0,
|
|
|
|
CS4231_LEFT_MIC_INPUT, CS4231_RIGHT_MIC_INPUT, 0, 0, 31, 1)
|
2005-04-17 02:20:36 +04:00
|
|
|
};
|
|
|
|
|
2008-07-31 23:03:41 +04:00
|
|
|
static int __devinit snd_interwave_mixer(struct snd_wss *chip)
|
2005-04-17 02:20:36 +04:00
|
|
|
{
|
2005-11-17 16:36:44 +03:00
|
|
|
struct snd_card *card = chip->card;
|
|
|
|
struct snd_ctl_elem_id id1, id2;
|
2005-04-17 02:20:36 +04:00
|
|
|
unsigned int idx;
|
|
|
|
int err;
|
|
|
|
|
|
|
|
memset(&id1, 0, sizeof(id1));
|
|
|
|
memset(&id2, 0, sizeof(id2));
|
|
|
|
id1.iface = id2.iface = SNDRV_CTL_ELEM_IFACE_MIXER;
|
|
|
|
#if 0
|
|
|
|
/* remove mono microphone controls */
|
|
|
|
strcpy(id1.name, "Mic Playback Switch");
|
|
|
|
if ((err = snd_ctl_remove_id(card, &id1)) < 0)
|
|
|
|
return err;
|
|
|
|
strcpy(id1.name, "Mic Playback Volume");
|
|
|
|
if ((err = snd_ctl_remove_id(card, &id1)) < 0)
|
|
|
|
return err;
|
|
|
|
#endif
|
|
|
|
/* add new master and mic controls */
|
|
|
|
for (idx = 0; idx < ARRAY_SIZE(snd_interwave_controls); idx++)
|
|
|
|
if ((err = snd_ctl_add(card, snd_ctl_new1(&snd_interwave_controls[idx], chip))) < 0)
|
|
|
|
return err;
|
2008-07-31 23:03:41 +04:00
|
|
|
snd_wss_out(chip, CS4231_LINE_LEFT_OUTPUT, 0x9f);
|
|
|
|
snd_wss_out(chip, CS4231_LINE_RIGHT_OUTPUT, 0x9f);
|
|
|
|
snd_wss_out(chip, CS4231_LEFT_MIC_INPUT, 0x9f);
|
|
|
|
snd_wss_out(chip, CS4231_RIGHT_MIC_INPUT, 0x9f);
|
2005-04-17 02:20:36 +04:00
|
|
|
/* reassign AUXA to SYNTHESIZER */
|
|
|
|
strcpy(id1.name, "Aux Playback Switch");
|
|
|
|
strcpy(id2.name, "Synth Playback Switch");
|
|
|
|
if ((err = snd_ctl_rename_id(card, &id1, &id2)) < 0)
|
|
|
|
return err;
|
|
|
|
strcpy(id1.name, "Aux Playback Volume");
|
|
|
|
strcpy(id2.name, "Synth Playback Volume");
|
|
|
|
if ((err = snd_ctl_rename_id(card, &id1, &id2)) < 0)
|
|
|
|
return err;
|
|
|
|
/* reassign AUXB to CD */
|
|
|
|
strcpy(id1.name, "Aux Playback Switch"); id1.index = 1;
|
|
|
|
strcpy(id2.name, "CD Playback Switch");
|
|
|
|
if ((err = snd_ctl_rename_id(card, &id1, &id2)) < 0)
|
|
|
|
return err;
|
|
|
|
strcpy(id1.name, "Aux Playback Volume");
|
|
|
|
strcpy(id2.name, "CD Playback Volume");
|
|
|
|
if ((err = snd_ctl_rename_id(card, &id1, &id2)) < 0)
|
|
|
|
return err;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
#ifdef CONFIG_PNP
|
|
|
|
|
|
|
|
static int __devinit snd_interwave_pnp(int dev, struct snd_interwave *iwcard,
|
|
|
|
struct pnp_card_link *card,
|
|
|
|
const struct pnp_card_device_id *id)
|
|
|
|
{
|
|
|
|
struct pnp_dev *pdev;
|
|
|
|
int err;
|
|
|
|
|
|
|
|
iwcard->dev = pnp_request_card_device(card, id->devs[0].id, NULL);
|
2007-11-30 19:59:25 +03:00
|
|
|
if (iwcard->dev == NULL)
|
2005-04-17 02:20:36 +04:00
|
|
|
return -EBUSY;
|
2007-11-30 19:59:25 +03:00
|
|
|
|
2005-04-17 02:20:36 +04:00
|
|
|
#ifdef SNDRV_STB
|
|
|
|
iwcard->devtc = pnp_request_card_device(card, id->devs[1].id, NULL);
|
2007-11-30 19:59:25 +03:00
|
|
|
if (iwcard->devtc == NULL)
|
2005-04-17 02:20:36 +04:00
|
|
|
return -EBUSY;
|
|
|
|
#endif
|
|
|
|
/* Synth & Codec initialization */
|
|
|
|
pdev = iwcard->dev;
|
2007-11-30 19:59:25 +03:00
|
|
|
|
2005-04-17 02:20:36 +04:00
|
|
|
err = pnp_activate_dev(pdev);
|
|
|
|
if (err < 0) {
|
|
|
|
snd_printk(KERN_ERR "InterWave PnP configure failure (out of resources?)\n");
|
|
|
|
return err;
|
|
|
|
}
|
|
|
|
if (pnp_port_start(pdev, 0) + 0x100 != pnp_port_start(pdev, 1) ||
|
|
|
|
pnp_port_start(pdev, 0) + 0x10c != pnp_port_start(pdev, 2)) {
|
|
|
|
snd_printk(KERN_ERR "PnP configure failure (wrong ports)\n");
|
|
|
|
return -ENOENT;
|
|
|
|
}
|
|
|
|
port[dev] = pnp_port_start(pdev, 0);
|
|
|
|
dma1[dev] = pnp_dma(pdev, 0);
|
|
|
|
if (dma2[dev] >= 0)
|
|
|
|
dma2[dev] = pnp_dma(pdev, 1);
|
|
|
|
irq[dev] = pnp_irq(pdev, 0);
|
2006-06-13 01:50:27 +04:00
|
|
|
snd_printdd("isapnp IW: sb port=0x%llx, gf1 port=0x%llx, codec port=0x%llx\n",
|
|
|
|
(unsigned long long)pnp_port_start(pdev, 0),
|
|
|
|
(unsigned long long)pnp_port_start(pdev, 1),
|
|
|
|
(unsigned long long)pnp_port_start(pdev, 2));
|
2005-04-17 02:20:36 +04:00
|
|
|
snd_printdd("isapnp IW: dma1=%i, dma2=%i, irq=%i\n", dma1[dev], dma2[dev], irq[dev]);
|
|
|
|
#ifdef SNDRV_STB
|
|
|
|
/* Tone Control initialization */
|
|
|
|
pdev = iwcard->devtc;
|
2007-11-30 19:59:25 +03:00
|
|
|
|
2005-04-17 02:20:36 +04:00
|
|
|
err = pnp_activate_dev(pdev);
|
|
|
|
if (err < 0) {
|
|
|
|
snd_printk(KERN_ERR "InterWave ToneControl PnP configure failure (out of resources?)\n");
|
|
|
|
return err;
|
|
|
|
}
|
|
|
|
port_tc[dev] = pnp_port_start(pdev, 0);
|
|
|
|
snd_printdd("isapnp IW: tone control port=0x%lx\n", port_tc[dev]);
|
|
|
|
#endif
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
#endif /* CONFIG_PNP */
|
|
|
|
|
2005-11-17 16:36:44 +03:00
|
|
|
static void snd_interwave_free(struct snd_card *card)
|
2005-04-17 02:20:36 +04:00
|
|
|
{
|
2005-11-17 19:13:43 +03:00
|
|
|
struct snd_interwave *iwcard = card->private_data;
|
2005-04-17 02:20:36 +04:00
|
|
|
|
|
|
|
if (iwcard == NULL)
|
|
|
|
return;
|
|
|
|
#ifdef SNDRV_STB
|
2005-10-10 13:56:31 +04:00
|
|
|
release_and_free_resource(iwcard->i2c_res);
|
2005-04-17 02:20:36 +04:00
|
|
|
#endif
|
|
|
|
if (iwcard->irq >= 0)
|
|
|
|
free_irq(iwcard->irq, (void *)iwcard);
|
|
|
|
}
|
|
|
|
|
2008-12-28 18:47:30 +03:00
|
|
|
static int snd_interwave_card_new(int dev, struct snd_card **cardp)
|
2005-04-17 02:20:36 +04:00
|
|
|
{
|
2005-11-17 16:36:44 +03:00
|
|
|
struct snd_card *card;
|
2005-04-17 02:20:36 +04:00
|
|
|
struct snd_interwave *iwcard;
|
2008-12-28 18:43:35 +03:00
|
|
|
int err;
|
2005-11-17 19:13:43 +03:00
|
|
|
|
2008-12-28 18:43:35 +03:00
|
|
|
err = snd_card_create(index[dev], id[dev], THIS_MODULE,
|
|
|
|
sizeof(struct snd_interwave), &card);
|
|
|
|
if (err < 0)
|
2008-12-28 18:47:30 +03:00
|
|
|
return err;
|
2005-11-17 19:13:43 +03:00
|
|
|
iwcard = card->private_data;
|
|
|
|
iwcard->card = card;
|
|
|
|
iwcard->irq = -1;
|
|
|
|
card->private_free = snd_interwave_free;
|
2008-12-28 18:47:30 +03:00
|
|
|
*cardp = card;
|
|
|
|
return 0;
|
2005-11-17 19:13:43 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
static int __devinit snd_interwave_probe(struct snd_card *card, int dev)
|
|
|
|
{
|
|
|
|
int xirq, xdma1, xdma2;
|
|
|
|
struct snd_interwave *iwcard = card->private_data;
|
2008-07-31 23:03:41 +04:00
|
|
|
struct snd_wss *wss;
|
2005-11-17 16:36:44 +03:00
|
|
|
struct snd_gus_card *gus;
|
2005-04-17 02:20:36 +04:00
|
|
|
#ifdef SNDRV_STB
|
2005-11-17 16:36:44 +03:00
|
|
|
struct snd_i2c_bus *i2c_bus;
|
2005-04-17 02:20:36 +04:00
|
|
|
#endif
|
2005-11-17 16:36:44 +03:00
|
|
|
struct snd_pcm *pcm;
|
2005-04-17 02:20:36 +04:00
|
|
|
char *str;
|
|
|
|
int err;
|
|
|
|
|
|
|
|
xirq = irq[dev];
|
|
|
|
xdma1 = dma1[dev];
|
|
|
|
xdma2 = dma2[dev];
|
|
|
|
|
|
|
|
if ((err = snd_gus_create(card,
|
|
|
|
port[dev],
|
|
|
|
-xirq, xdma1, xdma2,
|
|
|
|
0, 32,
|
[ALSA] Add snd_card_set_generic_dev() call to ISA drivers
ISA,CMI8330 driver,ES18xx driver,OPL3SA2 driver,Sound Galaxy driver
Sound Scape driver,AD1848 driver,CS4231 driver,CS4236+ driver
ES1688 driver,GUS Classic driver,GUS Extreme driver,GUS MAX driver
AMD InterWave driver,Opti9xx drivers,SB16/AWE driver,SB8 driver
Wavefront drivers
- Added snd_card_set_generic_dev() call.
- Added SND_GENERIC_DRIVER to Kconfig.
- Clean up the error path in probe if necessary.
Signed-off-by: Takashi Iwai <tiwai@suse.de>
2005-09-05 19:19:20 +04:00
|
|
|
pcm_channels[dev], effect[dev], &gus)) < 0)
|
2005-11-17 19:13:43 +03:00
|
|
|
return err;
|
[ALSA] Add snd_card_set_generic_dev() call to ISA drivers
ISA,CMI8330 driver,ES18xx driver,OPL3SA2 driver,Sound Galaxy driver
Sound Scape driver,AD1848 driver,CS4231 driver,CS4236+ driver
ES1688 driver,GUS Classic driver,GUS Extreme driver,GUS MAX driver
AMD InterWave driver,Opti9xx drivers,SB16/AWE driver,SB8 driver
Wavefront drivers
- Added snd_card_set_generic_dev() call.
- Added SND_GENERIC_DRIVER to Kconfig.
- Clean up the error path in probe if necessary.
Signed-off-by: Takashi Iwai <tiwai@suse.de>
2005-09-05 19:19:20 +04:00
|
|
|
|
2005-04-17 02:20:36 +04:00
|
|
|
if ((err = snd_interwave_detect(iwcard, gus, dev
|
|
|
|
#ifdef SNDRV_STB
|
|
|
|
, &i2c_bus
|
|
|
|
#endif
|
[ALSA] Add snd_card_set_generic_dev() call to ISA drivers
ISA,CMI8330 driver,ES18xx driver,OPL3SA2 driver,Sound Galaxy driver
Sound Scape driver,AD1848 driver,CS4231 driver,CS4236+ driver
ES1688 driver,GUS Classic driver,GUS Extreme driver,GUS MAX driver
AMD InterWave driver,Opti9xx drivers,SB16/AWE driver,SB8 driver
Wavefront drivers
- Added snd_card_set_generic_dev() call.
- Added SND_GENERIC_DRIVER to Kconfig.
- Clean up the error path in probe if necessary.
Signed-off-by: Takashi Iwai <tiwai@suse.de>
2005-09-05 19:19:20 +04:00
|
|
|
)) < 0)
|
2005-11-17 19:13:43 +03:00
|
|
|
return err;
|
[ALSA] Add snd_card_set_generic_dev() call to ISA drivers
ISA,CMI8330 driver,ES18xx driver,OPL3SA2 driver,Sound Galaxy driver
Sound Scape driver,AD1848 driver,CS4231 driver,CS4236+ driver
ES1688 driver,GUS Classic driver,GUS Extreme driver,GUS MAX driver
AMD InterWave driver,Opti9xx drivers,SB16/AWE driver,SB8 driver
Wavefront drivers
- Added snd_card_set_generic_dev() call.
- Added SND_GENERIC_DRIVER to Kconfig.
- Clean up the error path in probe if necessary.
Signed-off-by: Takashi Iwai <tiwai@suse.de>
2005-09-05 19:19:20 +04:00
|
|
|
|
2005-04-17 02:20:36 +04:00
|
|
|
iwcard->gus_status_reg = gus->gf1.reg_irqstat;
|
|
|
|
iwcard->pcm_status_reg = gus->gf1.port + 0x10c + 2;
|
|
|
|
|
|
|
|
snd_interwave_init(dev, gus);
|
|
|
|
snd_interwave_detect_memory(gus);
|
[ALSA] Add snd_card_set_generic_dev() call to ISA drivers
ISA,CMI8330 driver,ES18xx driver,OPL3SA2 driver,Sound Galaxy driver
Sound Scape driver,AD1848 driver,CS4231 driver,CS4236+ driver
ES1688 driver,GUS Classic driver,GUS Extreme driver,GUS MAX driver
AMD InterWave driver,Opti9xx drivers,SB16/AWE driver,SB8 driver
Wavefront drivers
- Added snd_card_set_generic_dev() call.
- Added SND_GENERIC_DRIVER to Kconfig.
- Clean up the error path in probe if necessary.
Signed-off-by: Takashi Iwai <tiwai@suse.de>
2005-09-05 19:19:20 +04:00
|
|
|
if ((err = snd_gus_initialize(gus)) < 0)
|
2005-11-17 19:13:43 +03:00
|
|
|
return err;
|
2005-04-17 02:20:36 +04:00
|
|
|
|
2006-07-02 06:29:46 +04:00
|
|
|
if (request_irq(xirq, snd_interwave_interrupt, IRQF_DISABLED,
|
2005-11-17 19:13:43 +03:00
|
|
|
"InterWave", iwcard)) {
|
[ALSA] Add snd_card_set_generic_dev() call to ISA drivers
ISA,CMI8330 driver,ES18xx driver,OPL3SA2 driver,Sound Galaxy driver
Sound Scape driver,AD1848 driver,CS4231 driver,CS4236+ driver
ES1688 driver,GUS Classic driver,GUS Extreme driver,GUS MAX driver
AMD InterWave driver,Opti9xx drivers,SB16/AWE driver,SB8 driver
Wavefront drivers
- Added snd_card_set_generic_dev() call.
- Added SND_GENERIC_DRIVER to Kconfig.
- Clean up the error path in probe if necessary.
Signed-off-by: Takashi Iwai <tiwai@suse.de>
2005-09-05 19:19:20 +04:00
|
|
|
snd_printk(KERN_ERR PFX "unable to grab IRQ %d\n", xirq);
|
2005-11-17 19:13:43 +03:00
|
|
|
return -EBUSY;
|
2005-04-17 02:20:36 +04:00
|
|
|
}
|
|
|
|
iwcard->irq = xirq;
|
|
|
|
|
2008-07-31 23:03:41 +04:00
|
|
|
err = snd_wss_create(card,
|
|
|
|
gus->gf1.port + 0x10c, -1, xirq,
|
|
|
|
xdma2 < 0 ? xdma1 : xdma2, xdma1,
|
|
|
|
WSS_HW_INTERWAVE,
|
|
|
|
WSS_HWSHARE_IRQ |
|
|
|
|
WSS_HWSHARE_DMA1 |
|
|
|
|
WSS_HWSHARE_DMA2,
|
|
|
|
&wss);
|
|
|
|
if (err < 0)
|
2005-11-17 19:13:43 +03:00
|
|
|
return err;
|
[ALSA] Add snd_card_set_generic_dev() call to ISA drivers
ISA,CMI8330 driver,ES18xx driver,OPL3SA2 driver,Sound Galaxy driver
Sound Scape driver,AD1848 driver,CS4231 driver,CS4236+ driver
ES1688 driver,GUS Classic driver,GUS Extreme driver,GUS MAX driver
AMD InterWave driver,Opti9xx drivers,SB16/AWE driver,SB8 driver
Wavefront drivers
- Added snd_card_set_generic_dev() call.
- Added SND_GENERIC_DRIVER to Kconfig.
- Clean up the error path in probe if necessary.
Signed-off-by: Takashi Iwai <tiwai@suse.de>
2005-09-05 19:19:20 +04:00
|
|
|
|
2008-07-31 23:03:41 +04:00
|
|
|
err = snd_wss_pcm(wss, 0, &pcm);
|
|
|
|
if (err < 0)
|
2005-11-17 19:13:43 +03:00
|
|
|
return err;
|
[ALSA] Add snd_card_set_generic_dev() call to ISA drivers
ISA,CMI8330 driver,ES18xx driver,OPL3SA2 driver,Sound Galaxy driver
Sound Scape driver,AD1848 driver,CS4231 driver,CS4236+ driver
ES1688 driver,GUS Classic driver,GUS Extreme driver,GUS MAX driver
AMD InterWave driver,Opti9xx drivers,SB16/AWE driver,SB8 driver
Wavefront drivers
- Added snd_card_set_generic_dev() call.
- Added SND_GENERIC_DRIVER to Kconfig.
- Clean up the error path in probe if necessary.
Signed-off-by: Takashi Iwai <tiwai@suse.de>
2005-09-05 19:19:20 +04:00
|
|
|
|
2005-04-17 02:20:36 +04:00
|
|
|
sprintf(pcm->name + strlen(pcm->name), " rev %c", gus->revision + 'A');
|
|
|
|
strcat(pcm->name, " (codec)");
|
[ALSA] Add snd_card_set_generic_dev() call to ISA drivers
ISA,CMI8330 driver,ES18xx driver,OPL3SA2 driver,Sound Galaxy driver
Sound Scape driver,AD1848 driver,CS4231 driver,CS4236+ driver
ES1688 driver,GUS Classic driver,GUS Extreme driver,GUS MAX driver
AMD InterWave driver,Opti9xx drivers,SB16/AWE driver,SB8 driver
Wavefront drivers
- Added snd_card_set_generic_dev() call.
- Added SND_GENERIC_DRIVER to Kconfig.
- Clean up the error path in probe if necessary.
Signed-off-by: Takashi Iwai <tiwai@suse.de>
2005-09-05 19:19:20 +04:00
|
|
|
|
2008-07-31 23:03:41 +04:00
|
|
|
err = snd_wss_timer(wss, 2, NULL);
|
|
|
|
if (err < 0)
|
2005-11-17 19:13:43 +03:00
|
|
|
return err;
|
[ALSA] Add snd_card_set_generic_dev() call to ISA drivers
ISA,CMI8330 driver,ES18xx driver,OPL3SA2 driver,Sound Galaxy driver
Sound Scape driver,AD1848 driver,CS4231 driver,CS4236+ driver
ES1688 driver,GUS Classic driver,GUS Extreme driver,GUS MAX driver
AMD InterWave driver,Opti9xx drivers,SB16/AWE driver,SB8 driver
Wavefront drivers
- Added snd_card_set_generic_dev() call.
- Added SND_GENERIC_DRIVER to Kconfig.
- Clean up the error path in probe if necessary.
Signed-off-by: Takashi Iwai <tiwai@suse.de>
2005-09-05 19:19:20 +04:00
|
|
|
|
2008-07-31 23:03:41 +04:00
|
|
|
err = snd_wss_mixer(wss);
|
|
|
|
if (err < 0)
|
2005-11-17 19:13:43 +03:00
|
|
|
return err;
|
[ALSA] Add snd_card_set_generic_dev() call to ISA drivers
ISA,CMI8330 driver,ES18xx driver,OPL3SA2 driver,Sound Galaxy driver
Sound Scape driver,AD1848 driver,CS4231 driver,CS4236+ driver
ES1688 driver,GUS Classic driver,GUS Extreme driver,GUS MAX driver
AMD InterWave driver,Opti9xx drivers,SB16/AWE driver,SB8 driver
Wavefront drivers
- Added snd_card_set_generic_dev() call.
- Added SND_GENERIC_DRIVER to Kconfig.
- Clean up the error path in probe if necessary.
Signed-off-by: Takashi Iwai <tiwai@suse.de>
2005-09-05 19:19:20 +04:00
|
|
|
|
2005-04-17 02:20:36 +04:00
|
|
|
if (pcm_channels[dev] > 0) {
|
2008-07-31 23:03:41 +04:00
|
|
|
err = snd_gf1_pcm_new(gus, 1, 1, NULL);
|
|
|
|
if (err < 0)
|
2005-11-17 19:13:43 +03:00
|
|
|
return err;
|
2005-04-17 02:20:36 +04:00
|
|
|
}
|
2008-07-31 23:03:41 +04:00
|
|
|
err = snd_interwave_mixer(wss);
|
|
|
|
if (err < 0)
|
2005-11-17 19:13:43 +03:00
|
|
|
return err;
|
[ALSA] Add snd_card_set_generic_dev() call to ISA drivers
ISA,CMI8330 driver,ES18xx driver,OPL3SA2 driver,Sound Galaxy driver
Sound Scape driver,AD1848 driver,CS4231 driver,CS4236+ driver
ES1688 driver,GUS Classic driver,GUS Extreme driver,GUS MAX driver
AMD InterWave driver,Opti9xx drivers,SB16/AWE driver,SB8 driver
Wavefront drivers
- Added snd_card_set_generic_dev() call.
- Added SND_GENERIC_DRIVER to Kconfig.
- Clean up the error path in probe if necessary.
Signed-off-by: Takashi Iwai <tiwai@suse.de>
2005-09-05 19:19:20 +04:00
|
|
|
|
2005-04-17 02:20:36 +04:00
|
|
|
#ifdef SNDRV_STB
|
|
|
|
{
|
2005-11-17 16:36:44 +03:00
|
|
|
struct snd_ctl_elem_id id1, id2;
|
2005-04-17 02:20:36 +04:00
|
|
|
memset(&id1, 0, sizeof(id1));
|
|
|
|
memset(&id2, 0, sizeof(id2));
|
|
|
|
id1.iface = id2.iface = SNDRV_CTL_ELEM_IFACE_MIXER;
|
|
|
|
strcpy(id1.name, "Master Playback Switch");
|
|
|
|
strcpy(id2.name, id1.name);
|
|
|
|
id2.index = 1;
|
[ALSA] Add snd_card_set_generic_dev() call to ISA drivers
ISA,CMI8330 driver,ES18xx driver,OPL3SA2 driver,Sound Galaxy driver
Sound Scape driver,AD1848 driver,CS4231 driver,CS4236+ driver
ES1688 driver,GUS Classic driver,GUS Extreme driver,GUS MAX driver
AMD InterWave driver,Opti9xx drivers,SB16/AWE driver,SB8 driver
Wavefront drivers
- Added snd_card_set_generic_dev() call.
- Added SND_GENERIC_DRIVER to Kconfig.
- Clean up the error path in probe if necessary.
Signed-off-by: Takashi Iwai <tiwai@suse.de>
2005-09-05 19:19:20 +04:00
|
|
|
if ((err = snd_ctl_rename_id(card, &id1, &id2)) < 0)
|
2005-11-17 19:13:43 +03:00
|
|
|
return err;
|
2005-04-17 02:20:36 +04:00
|
|
|
strcpy(id1.name, "Master Playback Volume");
|
|
|
|
strcpy(id2.name, id1.name);
|
[ALSA] Add snd_card_set_generic_dev() call to ISA drivers
ISA,CMI8330 driver,ES18xx driver,OPL3SA2 driver,Sound Galaxy driver
Sound Scape driver,AD1848 driver,CS4231 driver,CS4236+ driver
ES1688 driver,GUS Classic driver,GUS Extreme driver,GUS MAX driver
AMD InterWave driver,Opti9xx drivers,SB16/AWE driver,SB8 driver
Wavefront drivers
- Added snd_card_set_generic_dev() call.
- Added SND_GENERIC_DRIVER to Kconfig.
- Clean up the error path in probe if necessary.
Signed-off-by: Takashi Iwai <tiwai@suse.de>
2005-09-05 19:19:20 +04:00
|
|
|
if ((err = snd_ctl_rename_id(card, &id1, &id2)) < 0)
|
2005-11-17 19:13:43 +03:00
|
|
|
return err;
|
[ALSA] Add snd_card_set_generic_dev() call to ISA drivers
ISA,CMI8330 driver,ES18xx driver,OPL3SA2 driver,Sound Galaxy driver
Sound Scape driver,AD1848 driver,CS4231 driver,CS4236+ driver
ES1688 driver,GUS Classic driver,GUS Extreme driver,GUS MAX driver
AMD InterWave driver,Opti9xx drivers,SB16/AWE driver,SB8 driver
Wavefront drivers
- Added snd_card_set_generic_dev() call.
- Added SND_GENERIC_DRIVER to Kconfig.
- Clean up the error path in probe if necessary.
Signed-off-by: Takashi Iwai <tiwai@suse.de>
2005-09-05 19:19:20 +04:00
|
|
|
if ((err = snd_tea6330t_update_mixer(card, i2c_bus, 0, 1)) < 0)
|
2005-11-17 19:13:43 +03:00
|
|
|
return err;
|
2005-04-17 02:20:36 +04:00
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
gus->uart_enable = midi[dev];
|
[ALSA] Add snd_card_set_generic_dev() call to ISA drivers
ISA,CMI8330 driver,ES18xx driver,OPL3SA2 driver,Sound Galaxy driver
Sound Scape driver,AD1848 driver,CS4231 driver,CS4236+ driver
ES1688 driver,GUS Classic driver,GUS Extreme driver,GUS MAX driver
AMD InterWave driver,Opti9xx drivers,SB16/AWE driver,SB8 driver
Wavefront drivers
- Added snd_card_set_generic_dev() call.
- Added SND_GENERIC_DRIVER to Kconfig.
- Clean up the error path in probe if necessary.
Signed-off-by: Takashi Iwai <tiwai@suse.de>
2005-09-05 19:19:20 +04:00
|
|
|
if ((err = snd_gf1_rawmidi_new(gus, 0, NULL)) < 0)
|
2005-11-17 19:13:43 +03:00
|
|
|
return err;
|
2005-04-17 02:20:36 +04:00
|
|
|
|
|
|
|
#ifndef SNDRV_STB
|
|
|
|
str = "AMD InterWave";
|
|
|
|
if (gus->gf1.rom_banks == 1 && gus->gf1.rom_present == 8)
|
|
|
|
str = "Dynasonic 3-D";
|
|
|
|
#else
|
|
|
|
str = "InterWave STB";
|
|
|
|
#endif
|
|
|
|
strcpy(card->driver, str);
|
|
|
|
strcpy(card->shortname, str);
|
|
|
|
sprintf(card->longname, "%s at 0x%lx, irq %i, dma %d",
|
|
|
|
str,
|
|
|
|
gus->gf1.port,
|
|
|
|
xirq,
|
|
|
|
xdma1);
|
|
|
|
if (xdma2 >= 0)
|
|
|
|
sprintf(card->longname + strlen(card->longname), "&%d", xdma2);
|
|
|
|
|
2008-07-31 23:03:41 +04:00
|
|
|
err = snd_card_register(card);
|
|
|
|
if (err < 0)
|
2005-11-17 19:13:43 +03:00
|
|
|
return err;
|
2005-04-17 02:20:36 +04:00
|
|
|
|
2008-07-31 23:03:41 +04:00
|
|
|
iwcard->wss = wss;
|
2005-04-17 02:20:36 +04:00
|
|
|
iwcard->gus = gus;
|
|
|
|
return 0;
|
2005-11-17 19:13:43 +03:00
|
|
|
}
|
[ALSA] Add snd_card_set_generic_dev() call to ISA drivers
ISA,CMI8330 driver,ES18xx driver,OPL3SA2 driver,Sound Galaxy driver
Sound Scape driver,AD1848 driver,CS4231 driver,CS4236+ driver
ES1688 driver,GUS Classic driver,GUS Extreme driver,GUS MAX driver
AMD InterWave driver,Opti9xx drivers,SB16/AWE driver,SB8 driver
Wavefront drivers
- Added snd_card_set_generic_dev() call.
- Added SND_GENERIC_DRIVER to Kconfig.
- Clean up the error path in probe if necessary.
Signed-off-by: Takashi Iwai <tiwai@suse.de>
2005-09-05 19:19:20 +04:00
|
|
|
|
2007-02-22 14:50:54 +03:00
|
|
|
static int __devinit snd_interwave_isa_probe1(int dev, struct device *devptr)
|
2005-11-17 19:13:43 +03:00
|
|
|
{
|
|
|
|
struct snd_card *card;
|
|
|
|
int err;
|
|
|
|
|
2008-12-28 18:47:30 +03:00
|
|
|
err = snd_interwave_card_new(dev, &card);
|
|
|
|
if (err < 0)
|
|
|
|
return err;
|
2005-11-17 19:13:43 +03:00
|
|
|
|
2007-02-22 14:50:54 +03:00
|
|
|
snd_card_set_dev(card, devptr);
|
2005-11-17 19:13:43 +03:00
|
|
|
if ((err = snd_interwave_probe(card, dev)) < 0) {
|
|
|
|
snd_card_free(card);
|
|
|
|
return err;
|
|
|
|
}
|
2007-02-22 14:50:54 +03:00
|
|
|
dev_set_drvdata(devptr, card);
|
2005-11-17 19:13:43 +03:00
|
|
|
return 0;
|
2005-04-17 02:20:36 +04:00
|
|
|
}
|
|
|
|
|
2007-02-22 14:50:54 +03:00
|
|
|
static int __devinit snd_interwave_isa_match(struct device *pdev,
|
|
|
|
unsigned int dev)
|
|
|
|
{
|
|
|
|
if (!enable[dev])
|
|
|
|
return 0;
|
|
|
|
#ifdef CONFIG_PNP
|
|
|
|
if (isapnp[dev])
|
|
|
|
return 0;
|
|
|
|
#endif
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int __devinit snd_interwave_isa_probe(struct device *pdev,
|
|
|
|
unsigned int dev)
|
2005-04-17 02:20:36 +04:00
|
|
|
{
|
2005-11-17 19:13:43 +03:00
|
|
|
int err;
|
|
|
|
static int possible_irqs[] = {5, 11, 12, 9, 7, 15, 3, -1};
|
|
|
|
static int possible_dmas[] = {0, 1, 3, 5, 6, 7, -1};
|
2005-04-17 02:20:36 +04:00
|
|
|
|
2005-11-17 19:13:43 +03:00
|
|
|
if (irq[dev] == SNDRV_AUTO_IRQ) {
|
|
|
|
if ((irq[dev] = snd_legacy_find_free_irq(possible_irqs)) < 0) {
|
|
|
|
snd_printk(KERN_ERR PFX "unable to find a free IRQ\n");
|
|
|
|
return -EBUSY;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (dma1[dev] == SNDRV_AUTO_DMA) {
|
|
|
|
if ((dma1[dev] = snd_legacy_find_free_dma(possible_dmas)) < 0) {
|
|
|
|
snd_printk(KERN_ERR PFX "unable to find a free DMA1\n");
|
|
|
|
return -EBUSY;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (dma2[dev] == SNDRV_AUTO_DMA) {
|
|
|
|
if ((dma2[dev] = snd_legacy_find_free_dma(possible_dmas)) < 0) {
|
|
|
|
snd_printk(KERN_ERR PFX "unable to find a free DMA2\n");
|
|
|
|
return -EBUSY;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (port[dev] != SNDRV_AUTO_PORT)
|
2007-02-22 14:50:54 +03:00
|
|
|
return snd_interwave_isa_probe1(dev, pdev);
|
2005-11-17 19:13:43 +03:00
|
|
|
else {
|
|
|
|
static long possible_ports[] = {0x210, 0x220, 0x230, 0x240, 0x250, 0x260};
|
|
|
|
int i;
|
|
|
|
for (i = 0; i < ARRAY_SIZE(possible_ports); i++) {
|
|
|
|
port[dev] = possible_ports[i];
|
2007-02-22 14:50:54 +03:00
|
|
|
err = snd_interwave_isa_probe1(dev, pdev);
|
2005-11-17 19:13:43 +03:00
|
|
|
if (! err)
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
return err;
|
2005-04-17 02:20:36 +04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2007-02-22 14:50:54 +03:00
|
|
|
static int __devexit snd_interwave_isa_remove(struct device *devptr, unsigned int dev)
|
2005-11-17 19:13:43 +03:00
|
|
|
{
|
2007-02-22 14:50:54 +03:00
|
|
|
snd_card_free(dev_get_drvdata(devptr));
|
|
|
|
dev_set_drvdata(devptr, NULL);
|
2005-11-17 19:13:43 +03:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2007-02-22 14:50:54 +03:00
|
|
|
static struct isa_driver snd_interwave_driver = {
|
|
|
|
.match = snd_interwave_isa_match,
|
|
|
|
.probe = snd_interwave_isa_probe,
|
|
|
|
.remove = __devexit_p(snd_interwave_isa_remove),
|
2005-11-17 19:13:43 +03:00
|
|
|
/* FIXME: suspend,resume */
|
|
|
|
.driver = {
|
|
|
|
.name = INTERWAVE_DRIVER
|
|
|
|
},
|
|
|
|
};
|
|
|
|
|
2005-04-17 02:20:36 +04:00
|
|
|
#ifdef CONFIG_PNP
|
2005-11-17 19:13:43 +03:00
|
|
|
static int __devinit snd_interwave_pnp_detect(struct pnp_card_link *pcard,
|
|
|
|
const struct pnp_card_device_id *pid)
|
2005-04-17 02:20:36 +04:00
|
|
|
{
|
|
|
|
static int dev;
|
2005-11-17 19:13:43 +03:00
|
|
|
struct snd_card *card;
|
2005-04-17 02:20:36 +04:00
|
|
|
int res;
|
|
|
|
|
|
|
|
for ( ; dev < SNDRV_CARDS; dev++) {
|
2005-11-17 19:13:43 +03:00
|
|
|
if (enable[dev] && isapnp[dev])
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
if (dev >= SNDRV_CARDS)
|
|
|
|
return -ENODEV;
|
|
|
|
|
2008-12-28 18:47:30 +03:00
|
|
|
res = snd_interwave_card_new(dev, &card);
|
|
|
|
if (res < 0)
|
|
|
|
return res;
|
2005-11-17 19:13:43 +03:00
|
|
|
|
|
|
|
if ((res = snd_interwave_pnp(dev, card->private_data, pcard, pid)) < 0) {
|
|
|
|
snd_card_free(card);
|
|
|
|
return res;
|
|
|
|
}
|
|
|
|
snd_card_set_dev(card, &pcard->card->dev);
|
|
|
|
if ((res = snd_interwave_probe(card, dev)) < 0) {
|
|
|
|
snd_card_free(card);
|
|
|
|
return res;
|
|
|
|
}
|
|
|
|
pnp_set_card_drvdata(pcard, card);
|
|
|
|
dev++;
|
|
|
|
return 0;
|
2005-04-17 02:20:36 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
static void __devexit snd_interwave_pnp_remove(struct pnp_card_link * pcard)
|
|
|
|
{
|
2005-11-17 19:13:43 +03:00
|
|
|
snd_card_free(pnp_get_card_drvdata(pcard));
|
|
|
|
pnp_set_card_drvdata(pcard, NULL);
|
2005-04-17 02:20:36 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
static struct pnp_card_driver interwave_pnpc_driver = {
|
|
|
|
.flags = PNP_DRIVER_RES_DISABLE,
|
2005-11-17 19:13:43 +03:00
|
|
|
.name = INTERWAVE_PNP_DRIVER,
|
2005-04-17 02:20:36 +04:00
|
|
|
.id_table = snd_interwave_pnpids,
|
|
|
|
.probe = snd_interwave_pnp_detect,
|
|
|
|
.remove = __devexit_p(snd_interwave_pnp_remove),
|
2005-11-17 19:13:43 +03:00
|
|
|
/* FIXME: suspend,resume */
|
2005-04-17 02:20:36 +04:00
|
|
|
};
|
|
|
|
|
|
|
|
#endif /* CONFIG_PNP */
|
|
|
|
|
|
|
|
static int __init alsa_card_interwave_init(void)
|
|
|
|
{
|
2007-02-22 14:50:54 +03:00
|
|
|
int err;
|
2005-04-17 02:20:36 +04:00
|
|
|
|
2007-02-22 14:50:54 +03:00
|
|
|
err = isa_register_driver(&snd_interwave_driver, SNDRV_CARDS);
|
2005-04-17 02:20:36 +04:00
|
|
|
#ifdef CONFIG_PNP
|
2007-05-15 13:42:56 +04:00
|
|
|
if (!err)
|
|
|
|
isa_registered = 1;
|
|
|
|
|
2006-03-27 13:17:14 +04:00
|
|
|
err = pnp_register_card_driver(&interwave_pnpc_driver);
|
2007-02-22 14:50:54 +03:00
|
|
|
if (!err)
|
2005-12-07 11:13:42 +03:00
|
|
|
pnp_registered = 1;
|
2007-05-15 13:42:56 +04:00
|
|
|
|
|
|
|
if (isa_registered)
|
|
|
|
err = 0;
|
2005-04-17 02:20:36 +04:00
|
|
|
#endif
|
2007-05-15 13:42:56 +04:00
|
|
|
return err;
|
2005-04-17 02:20:36 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
static void __exit alsa_card_interwave_exit(void)
|
|
|
|
{
|
2007-02-22 14:50:54 +03:00
|
|
|
#ifdef CONFIG_PNP
|
|
|
|
if (pnp_registered)
|
|
|
|
pnp_unregister_card_driver(&interwave_pnpc_driver);
|
2007-05-15 13:42:56 +04:00
|
|
|
if (isa_registered)
|
2007-02-22 14:50:54 +03:00
|
|
|
#endif
|
2007-05-15 13:42:56 +04:00
|
|
|
isa_unregister_driver(&snd_interwave_driver);
|
2005-04-17 02:20:36 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
module_init(alsa_card_interwave_init)
|
|
|
|
module_exit(alsa_card_interwave_exit)
|