summaryrefslogtreecommitdiffstats
path: root/sound/isa
diff options
context:
space:
mode:
Diffstat (limited to 'sound/isa')
-rw-r--r--sound/isa/Kconfig63
-rw-r--r--sound/isa/Makefile2
-rw-r--r--sound/isa/ad1816a/ad1816a.c21
-rw-r--r--sound/isa/ad1816a/ad1816a_lib.c11
-rw-r--r--sound/isa/ad1848/ad1848.c6
-rw-r--r--sound/isa/adlib.c6
-rw-r--r--sound/isa/als100.c7
-rw-r--r--sound/isa/azt2320.c7
-rw-r--r--sound/isa/cmi8330.c94
-rw-r--r--sound/isa/cs423x/Makefile8
-rw-r--r--sound/isa/cs423x/cs4231.c6
-rw-r--r--sound/isa/cs423x/cs4232.c2
-rw-r--r--sound/isa/cs423x/cs4236.c185
-rw-r--r--sound/isa/cs423x/cs4236_lib.c45
-rw-r--r--sound/isa/dt019x.c7
-rw-r--r--sound/isa/es1688/es1688.c29
-rw-r--r--sound/isa/es1688/es1688_lib.c23
-rw-r--r--sound/isa/es18xx.c24
-rw-r--r--sound/isa/gus/gus_dma.c27
-rw-r--r--sound/isa/gus/gus_irq.c6
-rw-r--r--sound/isa/gus/gus_pcm.c26
-rw-r--r--sound/isa/gus/gus_uart.c10
-rw-r--r--sound/isa/gus/gusclassic.c6
-rw-r--r--sound/isa/gus/gusextreme.c6
-rw-r--r--sound/isa/gus/gusmax.c8
-rw-r--r--sound/isa/gus/interwave.c42
-rw-r--r--sound/isa/msnd/Makefile9
-rw-r--r--sound/isa/msnd/msnd.c705
-rw-r--r--sound/isa/msnd/msnd.h308
-rw-r--r--sound/isa/msnd/msnd_classic.c3
-rw-r--r--sound/isa/msnd/msnd_classic.h129
-rw-r--r--sound/isa/msnd/msnd_midi.c180
-rw-r--r--sound/isa/msnd/msnd_pinnacle.c1238
-rw-r--r--sound/isa/msnd/msnd_pinnacle.h181
-rw-r--r--sound/isa/msnd/msnd_pinnacle_mixer.c343
-rw-r--r--sound/isa/opl3sa2.c45
-rw-r--r--sound/isa/opti9xx/miro.c7
-rw-r--r--sound/isa/opti9xx/opti92x-ad1848.c65
-rw-r--r--sound/isa/sb/es968.c7
-rw-r--r--sound/isa/sb/sb16.c28
-rw-r--r--sound/isa/sb/sb8.c8
-rw-r--r--sound/isa/sb/sb_mixer.c156
-rw-r--r--sound/isa/sc6000.c10
-rw-r--r--sound/isa/sgalaxy.c6
-rw-r--r--sound/isa/sscape.c205
-rw-r--r--sound/isa/wavefront/wavefront.c30
-rw-r--r--sound/isa/wavefront/wavefront_synth.c2
-rw-r--r--sound/isa/wss/wss_lib.c160
48 files changed, 3865 insertions, 637 deletions
diff --git a/sound/isa/Kconfig b/sound/isa/Kconfig
index ce0aa044e27..c5c9a9218ff 100644
--- a/sound/isa/Kconfig
+++ b/sound/isa/Kconfig
@@ -56,8 +56,8 @@ config SND_AD1848
Say Y here to include support for AD1848 (Analog Devices) or
CS4248 (Cirrus Logic - Crystal Semiconductors) chips.
- For newer chips from Cirrus Logic, use the CS4231, CS4232 or
- CS4236+ drivers.
+ For newer chips from Cirrus Logic, use the CS4231 or CS4232+
+ drivers.
To compile this driver as a module, choose M here: the module
will be called snd-ad1848.
@@ -94,6 +94,8 @@ config SND_CMI8330
tristate "C-Media CMI8330"
select SND_WSS_LIB
select SND_SB16_DSP
+ select SND_OPL3_LIB
+ select SND_MPU401_UART
help
Say Y here to include support for soundcards based on the
C-Media CMI8330 chip.
@@ -112,26 +114,15 @@ config SND_CS4231
To compile this driver as a module, choose M here: the module
will be called snd-cs4231.
-config SND_CS4232
- tristate "Generic Cirrus Logic CS4232 driver"
- select SND_OPL3_LIB
- select SND_MPU401_UART
- select SND_WSS_LIB
- help
- Say Y here to include support for CS4232 chips from Cirrus
- Logic - Crystal Semiconductors.
-
- To compile this driver as a module, choose M here: the module
- will be called snd-cs4232.
-
config SND_CS4236
- tristate "Generic Cirrus Logic CS4236+ driver"
+ tristate "Generic Cirrus Logic CS4232/CS4236+ driver"
select SND_OPL3_LIB
select SND_MPU401_UART
select SND_WSS_LIB
help
- Say Y to include support for CS4235,CS4236,CS4237B,CS4238B,
- CS4239 chips from Cirrus Logic - Crystal Semiconductors.
+ Say Y to include support for CS4232,CS4235,CS4236,CS4237B,
+ CS4238B,CS4239 chips from Cirrus Logic - Crystal
+ Semiconductors.
To compile this driver as a module, choose M here: the module
will be called snd-cs4236.
@@ -377,14 +368,17 @@ config SND_SGALAXY
will be called snd-sgalaxy.
config SND_SSCAPE
- tristate "Ensoniq SoundScape PnP driver"
+ tristate "Ensoniq SoundScape driver"
select SND_HWDEP
select SND_MPU401_UART
select SND_WSS_LIB
help
- Say Y here to include support for Ensoniq SoundScape PnP
+ Say Y here to include support for Ensoniq SoundScape
soundcards.
+ The PCM audio is supported on SoundScape Classic, Elite, PnP
+ and VIVO cards. The MIDI support is very experimental.
+
To compile this driver as a module, choose M here: the module
will be called snd-sscape.
@@ -411,5 +405,36 @@ config SND_WAVEFRONT_FIRMWARE_IN_KERNEL
you need to install the firmware files from the
alsa-firmware package.
+config SND_MSND_PINNACLE
+ tristate "Turtle Beach MultiSound Pinnacle/Fiji driver"
+ depends on X86 && EXPERIMENTAL
+ select FW_LOADER
+ select SND_MPU401_UART
+ select SND_PCM
+ help
+ Say Y to include support for Turtle Beach MultiSound Pinnacle/
+ Fiji soundcards.
+
+ To compile this driver as a module, choose M here: the module
+ will be called snd-msnd-pinnacle.
+
+config SND_MSND_CLASSIC
+ tristate "Support for Turtle Beach MultiSound Classic, Tahiti, Monterey"
+ depends on X86 && EXPERIMENTAL
+ select FW_LOADER
+ select SND_MPU401_UART
+ select SND_PCM
+ help
+ Say M here if you have a Turtle Beach MultiSound Classic, Tahiti or
+ Monterey (not for the Pinnacle or Fiji).
+
+ See <file:Documentation/sound/oss/MultiSound> for important information
+ about this driver. Note that it has been discontinued, but the
+ Voyetra Turtle Beach knowledge base entry for it is still available
+ at <http://www.turtlebeach.com/site/kb_ftp/790.asp>.
+
+ To compile this driver as a module, choose M here: the module
+ will be called snd-msnd-classic.
+
endif # SND_ISA
diff --git a/sound/isa/Makefile b/sound/isa/Makefile
index 63af13d901a..b906b9a1a81 100644
--- a/sound/isa/Makefile
+++ b/sound/isa/Makefile
@@ -26,5 +26,5 @@ obj-$(CONFIG_SND_SC6000) += snd-sc6000.o
obj-$(CONFIG_SND_SGALAXY) += snd-sgalaxy.o
obj-$(CONFIG_SND_SSCAPE) += snd-sscape.o
-obj-$(CONFIG_SND) += ad1816a/ ad1848/ cs423x/ es1688/ gus/ opti9xx/ \
+obj-$(CONFIG_SND) += ad1816a/ ad1848/ cs423x/ es1688/ gus/ msnd/ opti9xx/ \
sb/ wavefront/ wss/
diff --git a/sound/isa/ad1816a/ad1816a.c b/sound/isa/ad1816a/ad1816a.c
index 77524244a84..bbcbf92a8eb 100644
--- a/sound/isa/ad1816a/ad1816a.c
+++ b/sound/isa/ad1816a/ad1816a.c
@@ -156,10 +156,12 @@ static int __devinit snd_card_ad1816a_probe(int dev, struct pnp_card_link *pcard
struct snd_card_ad1816a *acard;
struct snd_ad1816a *chip;
struct snd_opl3 *opl3;
+ struct snd_timer *timer;
- if ((card = snd_card_new(index[dev], id[dev], THIS_MODULE,
- sizeof(struct snd_card_ad1816a))) == NULL)
- return -ENOMEM;
+ error = snd_card_create(index[dev], id[dev], THIS_MODULE,
+ sizeof(struct snd_card_ad1816a), &card);
+ if (error < 0)
+ return error;
acard = (struct snd_card_ad1816a *)card->private_data;
if ((error = snd_card_ad1816a_pnp(dev, acard, pcard, pid))) {
@@ -194,6 +196,12 @@ static int __devinit snd_card_ad1816a_probe(int dev, struct pnp_card_link *pcard
return error;
}
+ error = snd_ad1816a_timer(chip, 0, &timer);
+ if (error < 0) {
+ snd_card_free(card);
+ return error;
+ }
+
if (mpu_port[dev] > 0) {
if (snd_mpu401_uart_new(card, 0, MPU401_HW_MPU401,
mpu_port[dev], 0, mpu_irq[dev], IRQF_DISABLED,
@@ -207,11 +215,8 @@ static int __devinit snd_card_ad1816a_probe(int dev, struct pnp_card_link *pcard
OPL3_HW_AUTO, 0, &opl3) < 0) {
printk(KERN_ERR PFX "no OPL device at 0x%lx-0x%lx.\n", fm_port[dev], fm_port[dev] + 2);
} else {
- if ((error = snd_opl3_timer_new(opl3, 1, 2)) < 0) {
- snd_card_free(card);
- return error;
- }
- if ((error = snd_opl3_hwdep_new(opl3, 0, 1, NULL)) < 0) {
+ error = snd_opl3_hwdep_new(opl3, 0, 1, NULL);
+ if (error < 0) {
snd_card_free(card);
return error;
}
diff --git a/sound/isa/ad1816a/ad1816a_lib.c b/sound/isa/ad1816a/ad1816a_lib.c
index 3bfca7c59ba..05aef8b97e9 100644
--- a/sound/isa/ad1816a/ad1816a_lib.c
+++ b/sound/isa/ad1816a/ad1816a_lib.c
@@ -37,7 +37,7 @@ static inline int snd_ad1816a_busy_wait(struct snd_ad1816a *chip)
if (inb(AD1816A_REG(AD1816A_CHIP_STATUS)) & AD1816A_READY)
return 0;
- snd_printk("chip busy.\n");
+ snd_printk(KERN_WARNING "chip busy.\n");
return -EBUSY;
}
@@ -196,7 +196,7 @@ static int snd_ad1816a_trigger(struct snd_ad1816a *chip, unsigned char what,
spin_unlock(&chip->lock);
break;
default:
- snd_printk("invalid trigger mode 0x%x.\n", what);
+ snd_printk(KERN_WARNING "invalid trigger mode 0x%x.\n", what);
error = -EINVAL;
}
@@ -377,7 +377,6 @@ static struct snd_pcm_hardware snd_ad1816a_capture = {
.fifo_size = 0,
};
-#if 0 /* not used now */
static int snd_ad1816a_timer_close(struct snd_timer *timer)
{
struct snd_ad1816a *chip = snd_timer_chip(timer);
@@ -442,8 +441,6 @@ static struct snd_timer_hardware snd_ad1816a_timer_table = {
.start = snd_ad1816a_timer_start,
.stop = snd_ad1816a_timer_stop,
};
-#endif /* not used now */
-
static int snd_ad1816a_playback_open(struct snd_pcm_substream *substream)
{
@@ -568,7 +565,7 @@ static const char __devinit *snd_ad1816a_chip_id(struct snd_ad1816a *chip)
case AD1816A_HW_AD1815: return "AD1815";
case AD1816A_HW_AD18MAX10: return "AD18max10";
default:
- snd_printk("Unknown chip version %d:%d.\n",
+ snd_printk(KERN_WARNING "Unknown chip version %d:%d.\n",
chip->version, chip->hardware);
return "AD1816A - unknown";
}
@@ -687,7 +684,6 @@ int __devinit snd_ad1816a_pcm(struct snd_ad1816a *chip, int device, struct snd_p
return 0;
}
-#if 0 /* not used now */
int __devinit snd_ad1816a_timer(struct snd_ad1816a *chip, int device, struct snd_timer **rtimer)
{
struct snd_timer *timer;
@@ -709,7 +705,6 @@ int __devinit snd_ad1816a_timer(struct snd_ad1816a *chip, int device, struct snd
*rtimer = timer;
return 0;
}
-#endif /* not used now */
/*
*
diff --git a/sound/isa/ad1848/ad1848.c b/sound/isa/ad1848/ad1848.c
index 223a6c03881..4beeb6f98e0 100644
--- a/sound/isa/ad1848/ad1848.c
+++ b/sound/isa/ad1848/ad1848.c
@@ -91,9 +91,9 @@ static int __devinit snd_ad1848_probe(struct device *dev, unsigned int n)
struct snd_pcm *pcm;
int error;
- card = snd_card_new(index[n], id[n], THIS_MODULE, 0);
- if (!card)
- return -EINVAL;
+ error = snd_card_create(index[n], id[n], THIS_MODULE, 0, &card);
+ if (error < 0)
+ return error;
error = snd_wss_create(card, port[n], -1, irq[n], dma1[n], -1,
thinkpad[n] ? WSS_HW_THINKPAD : WSS_HW_DETECT,
diff --git a/sound/isa/adlib.c b/sound/isa/adlib.c
index 374b7177e11..7465ae036e0 100644
--- a/sound/isa/adlib.c
+++ b/sound/isa/adlib.c
@@ -53,10 +53,10 @@ static int __devinit snd_adlib_probe(struct device *dev, unsigned int n)
struct snd_opl3 *opl3;
int error;
- card = snd_card_new(index[n], id[n], THIS_MODULE, 0);
- if (!card) {
+ error = snd_card_create(index[n], id[n], THIS_MODULE, 0, &card);
+ if (error < 0) {
dev_err(dev, "could not create card\n");
- return -EINVAL;
+ return error;
}
card->private_data = request_region(port[n], 4, CRD_NAME);
diff --git a/sound/isa/als100.c b/sound/isa/als100.c
index f1ce30f379c..5fd52e4d707 100644
--- a/sound/isa/als100.c
+++ b/sound/isa/als100.c
@@ -163,9 +163,10 @@ static int __devinit snd_card_als100_probe(int dev,
struct snd_card_als100 *acard;
struct snd_opl3 *opl3;
- if ((card = snd_card_new(index[dev], id[dev], THIS_MODULE,
- sizeof(struct snd_card_als100))) == NULL)
- return -ENOMEM;
+ error = snd_card_create(index[dev], id[dev], THIS_MODULE,
+ sizeof(struct snd_card_als100), &card);
+ if (error < 0)
+ return error;
acard = card->private_data;
if ((error = snd_card_als100_pnp(dev, acard, pcard, pid))) {
diff --git a/sound/isa/azt2320.c b/sound/isa/azt2320.c
index 3e74d1a3928..f7aa637b0d1 100644
--- a/sound/isa/azt2320.c
+++ b/sound/isa/azt2320.c
@@ -184,9 +184,10 @@ static int __devinit snd_card_azt2320_probe(int dev,
struct snd_wss *chip;
struct snd_opl3 *opl3;
- if ((card = snd_card_new(index[dev], id[dev], THIS_MODULE,
- sizeof(struct snd_card_azt2320))) == NULL)
- return -ENOMEM;
+ error = snd_card_create(index[dev], id[dev], THIS_MODULE,
+ sizeof(struct snd_card_azt2320), &card);
+ if (error < 0)
+ return error;
acard = (struct snd_card_azt2320 *)card->private_data;
if ((error = snd_card_azt2320_pnp(dev, acard, pcard, pid))) {
diff --git a/sound/isa/cmi8330.c b/sound/isa/cmi8330.c
index e49aec700a5..de83608719e 100644
--- a/sound/isa/cmi8330.c
+++ b/sound/isa/cmi8330.c
@@ -31,11 +31,11 @@
* To quickly load the module,
*
* modprobe -a snd-cmi8330 sbport=0x220 sbirq=5 sbdma8=1
- * sbdma16=5 wssport=0x530 wssirq=11 wssdma=0
+ * sbdma16=5 wssport=0x530 wssirq=11 wssdma=0 fmport=0x388
*
* This card has two mixers and two PCM devices. I've cheesed it such
* that recording and playback can be done through the same device.
- * The driver "magically" routes the capturing to the AD1848 codec,
+ * The driver "magically" routes the capturing to the CMI8330 codec,
* and playback to the SB16 codec. This allows for full-duplex mode
* to some extent.
* The utilities in alsa-utils are aware of both devices, so passing
@@ -51,6 +51,8 @@
#include <linux/moduleparam.h>
#include <sound/core.h>
#include <sound/wss.h>
+#include <sound/opl3.h>
+#include <sound/mpu401.h>
#include <sound/sb.h>
#include <sound/initval.h>
@@ -79,6 +81,9 @@ static int sbdma16[SNDRV_CARDS] = SNDRV_DEFAULT_DMA;
static long wssport[SNDRV_CARDS] = SNDRV_DEFAULT_PORT;
static int wssirq[SNDRV_CARDS] = SNDRV_DEFAULT_IRQ;
static int wssdma[SNDRV_CARDS] = SNDRV_DEFAULT_DMA;
+static long fmport[SNDRV_CARDS] = SNDRV_DEFAULT_PORT;
+static long mpuport[SNDRV_CARDS] = SNDRV_DEFAULT_PORT;
+static int mpuirq[SNDRV_CARDS] = SNDRV_DEFAULT_IRQ;
module_param_array(index, int, NULL, 0444);
MODULE_PARM_DESC(index, "Index value for CMI8330 soundcard.");
@@ -107,6 +112,12 @@ MODULE_PARM_DESC(wssirq, "IRQ # for CMI8330 WSS driver.");
module_param_array(wssdma, int, NULL, 0444);
MODULE_PARM_DESC(wssdma, "DMA for CMI8330 WSS driver.");
+module_param_array(fmport, long, NULL, 0444);
+MODULE_PARM_DESC(fmport, "FM port # for CMI8330 driver.");
+module_param_array(mpuport, long, NULL, 0444);
+MODULE_PARM_DESC(mpuport, "MPU-401 port # for CMI8330 driver.");
+module_param_array(mpuirq, int, NULL, 0444);
+MODULE_PARM_DESC(mpuirq, "IRQ # for CMI8330 MPU-401 port.");
#ifdef CONFIG_PNP
static int isa_registered;
static int pnp_registered;
@@ -149,6 +160,7 @@ struct snd_cmi8330 {
#ifdef CONFIG_PNP
struct pnp_dev *cap;
struct pnp_dev *play;
+ struct pnp_dev *mpu;
#endif
struct snd_card *card;
struct snd_wss *wss;
@@ -165,7 +177,7 @@ struct snd_cmi8330 {
#ifdef CONFIG_PNP
static struct pnp_card_device_id snd_cmi8330_pnpids[] = {
- { .id = "CMI0001", .devs = { { "@@@0001" }, { "@X@0001" } } },
+ { .id = "CMI0001", .devs = { { "@@@0001" }, { "@X@0001" }, { "@H@0001" } } },
{ .id = "" }
};
@@ -219,8 +231,10 @@ WSS_SINGLE("3D Control - Switch", 0,
CMI8330_RMUX3D, 5, 1, 1),
WSS_SINGLE("PC Speaker Playback Volume", 0,
CMI8330_OUTPUTVOL, 3, 3, 0),
-WSS_SINGLE("FM Playback Switch", 0,
- CMI8330_RECMUX, 3, 1, 1),
+WSS_DOUBLE("FM Playback Switch", 0,
+ CS4231_AUX2_LEFT_INPUT, CS4231_AUX2_RIGHT_INPUT, 7, 7, 1, 1),
+WSS_DOUBLE("FM Playback Volume", 0,
+ CS4231_AUX2_LEFT_INPUT, CS4231_AUX2_RIGHT_INPUT, 0, 0, 31, 1),
WSS_SINGLE(SNDRV_CTL_NAME_IEC958("Input ", CAPTURE, SWITCH), 0,
CMI8330_RMUX3D, 7, 1, 1),
WSS_SINGLE(SNDRV_CTL_NAME_IEC958("Input ", PLAYBACK, SWITCH), 0,
@@ -323,16 +337,21 @@ static int __devinit snd_cmi8330_pnp(int dev, struct snd_cmi8330 *acard,
if (acard->play == NULL)
return -EBUSY;
+ acard->mpu = pnp_request_card_device(card, id->devs[2].id, NULL);
+ if (acard->play == NULL)
+ return -EBUSY;
+
pdev = acard->cap;
err = pnp_activate_dev(pdev);
if (err < 0) {
- snd_printk(KERN_ERR "CMI8330/C3D (AD1848) PnP configure failure\n");
+ snd_printk(KERN_ERR "CMI8330/C3D PnP configure failure\n");
return -EBUSY;
}
wssport[dev] = pnp_port_start(pdev, 0);
wssdma[dev] = pnp_dma(pdev, 0);
wssirq[dev] = pnp_irq(pdev, 0);
+ fmport[dev] = pnp_port_start(pdev, 1);
/* allocate SB16 resources */
pdev = acard->play;
@@ -347,6 +366,17 @@ static int __devinit snd_cmi8330_pnp(int dev, struct snd_cmi8330 *acard,
sbdma16[dev] = pnp_dma(pdev, 1);
sbirq[dev] = pnp_irq(pdev, 0);
+ /* allocate MPU-401 resources */
+ pdev = acard->mpu;
+
+ err = pnp_activate_dev(pdev);
+ if (err < 0) {
+ snd_printk(KERN_ERR
+ "CMI8330/C3D (MPU-401) PnP configure failure\n");
+ return -EBUSY;
+ }
+ mpuport[dev] = pnp_port_start(pdev, 0);
+ mpuirq[dev] = pnp_irq(pdev, 0);
return 0;
}
#endif
@@ -467,26 +497,29 @@ static int snd_cmi8330_resume(struct snd_card *card)
#define PFX "cmi8330: "
-static struct snd_card *snd_cmi8330_card_new(int dev)
+static int snd_cmi8330_card_new(int dev, struct snd_card **cardp)
{
struct snd_card *card;
struct snd_cmi8330 *acard;
+ int err;
- card = snd_card_new(index[dev], id[dev], THIS_MODULE,
- sizeof(struct snd_cmi8330));
- if (card == NULL) {
+ err = snd_card_create(index[dev], id[dev], THIS_MODULE,
+ sizeof(struct snd_cmi8330), &card);
+ if (err < 0) {
snd_printk(KERN_ERR PFX "could not get a new card\n");
- return NULL;
+ return err;
}
acard = card->private_data;
acard->card = card;
- return card;
+ *cardp = card;
+ return 0;
}
static int __devinit snd_cmi8330_probe(struct snd_card *card, int dev)
{
struct snd_cmi8330 *acard;
int i, err;
+ struct snd_opl3 *opl3;
acard = card->private_data;
err = snd_wss_create(card, wssport[dev] + 4, -1,
@@ -494,11 +527,11 @@ static int __devinit snd_cmi8330_probe(struct snd_card *card, int dev)
wssdma[dev], -1,
WSS_HW_DETECT, 0, &acard->wss);
if (err < 0) {
- snd_printk(KERN_ERR PFX "(AD1848) device busy??\n");
+ snd_printk(KERN_ERR PFX "(CMI8330) device busy??\n");
return err;
}
if (acard->wss->hardware != WSS_HW_CMI8330) {
- snd_printk(KERN_ERR PFX "(AD1848) not found during probe\n");
+ snd_printk(KERN_ERR PFX "(CMI8330) not found during probe\n");
return -ENODEV;
}
@@ -530,6 +563,27 @@ static int __devinit snd_cmi8330_probe(struct snd_card *card, int dev)
snd_printk(KERN_ERR PFX "failed to create pcms\n");
return err;
}
+ if (fmport[dev] != SNDRV_AUTO_PORT) {
+ if (snd_opl3_create(card,
+ fmport[dev], fmport[dev] + 2,
+ OPL3_HW_AUTO, 0, &opl3) < 0) {
+ snd_printk(KERN_ERR PFX
+ "no OPL device at 0x%lx-0x%lx ?\n",
+ fmport[dev], fmport[dev] + 2);
+ } else {
+ err = snd_opl3_hwdep_new(opl3, 0, 1, NULL);
+ if (err < 0)
+ return err;
+ }
+ }
+
+ if (mpuport[dev] != SNDRV_AUTO_PORT) {
+ if (snd_mpu401_uart_new(card, 0, MPU401_HW_MPU401,
+ mpuport[dev], 0, mpuirq[dev],
+ IRQF_DISABLED, NULL) < 0)
+ printk(KERN_ERR PFX "no MPU-401 device at 0x%lx.\n",
+ mpuport[dev]);
+ }
strcpy(card->driver, "CMI8330/C3D");
strcpy(card->shortname, "C-Media CMI8330/C3D");
@@ -564,9 +618,9 @@ static int __devinit snd_cmi8330_isa_probe(struct device *pdev,
struct snd_card *card;
int err;
- card = snd_cmi8330_card_new(dev);
- if (! card)
- return -ENOMEM;
+ err = snd_cmi8330_card_new(dev, &card);
+ if (err < 0)
+ return err;
snd_card_set_dev(card, pdev);
if ((err = snd_cmi8330_probe(card, dev)) < 0) {
snd_card_free(card);
@@ -628,9 +682,9 @@ static int __devinit snd_cmi8330_pnp_detect(struct pnp_card_link *pcard,
if (dev >= SNDRV_CARDS)
return -ENODEV;
- card = snd_cmi8330_card_new(dev);
- if (! card)
- return -ENOMEM;
+ res = snd_cmi8330_card_new(dev, &card);
+ if (res < 0)
+ return res;
if ((res = snd_cmi8330_pnp(dev, card->private_data, pcard, pid)) < 0) {
snd_printk(KERN_ERR PFX "PnP detection failed\n");
snd_card_free(card);
diff --git a/sound/isa/cs423x/Makefile b/sound/isa/cs423x/Makefile
index 5870ca21ab5..6d397e8d54a 100644
--- a/sound/isa/cs423x/Makefile
+++ b/sound/isa/cs423x/Makefile
@@ -3,13 +3,11 @@
# Copyright (c) 2001 by Jaroslav Kysela <perex@perex.cz>
#
-snd-cs4236-lib-objs := cs4236_lib.o
snd-cs4231-objs := cs4231.o
-snd-cs4232-objs := cs4232.o
-snd-cs4236-objs := cs4236.o
+snd-cs4236-objs := cs4236.o cs4236_lib.o
# Toplevel Module Dependency
obj-$(CONFIG_SND_CS4231) += snd-cs4231.o
-obj-$(CONFIG_SND_CS4232) += snd-cs4232.o
-obj-$(CONFIG_SND_CS4236) += snd-cs4236.o snd-cs4236-lib.o
+obj-$(CONFIG_SND_CS4236) += snd-cs4236.o
+
diff --git a/sound/isa/cs423x/cs4231.c b/sound/isa/cs423x/cs4231.c
index f019d449e2d..cb9153e75b8 100644
--- a/sound/isa/cs423x/cs4231.c
+++ b/sound/isa/cs423x/cs4231.c
@@ -95,9 +95,9 @@ static int __devinit snd_cs4231_probe(struct device *dev, unsigned int n)
struct snd_pcm *pcm;
int error;
- card = snd_card_new(index[n], id[n], THIS_MODULE, 0);
- if (!card)
- return -EINVAL;
+ error = snd_card_create(index[n], id[n], THIS_MODULE, 0, &card);
+ if (error < 0)
+ return error;
error = snd_wss_create(card, port[n], -1, irq[n], dma1[n], dma2[n],
WSS_HW_DETECT, 0, &chip);
diff --git a/sound/isa/cs423x/cs4232.c b/sound/isa/cs423x/cs4232.c
deleted file mode 100644
index 9fad2e6c0c2..00000000000
--- a/sound/isa/cs423x/cs4232.c
+++ /dev/null
@@ -1,2 +0,0 @@
-#define CS4232
-#include "cs4236.c"
diff --git a/sound/isa/cs423x/cs4236.c b/sound/isa/cs423x/cs4236.c
index 019c9401663..a076a6ce807 100644
--- a/sound/isa/cs423x/cs4236.c
+++ b/sound/isa/cs423x/cs4236.c
@@ -33,17 +33,14 @@
MODULE_AUTHOR("Jaroslav Kysela <perex@perex.cz>");
MODULE_LICENSE("GPL");
-#ifdef CS4232
-MODULE_DESCRIPTION("Cirrus Logic CS4232");
+MODULE_DESCRIPTION("Cirrus Logic CS4232-9");
MODULE_SUPPORTED_DEVICE("{{Turtle Beach,TBS-2000},"
"{Turtle Beach,Tropez Plus},"
"{SIC CrystalWave 32},"
"{Hewlett Packard,Omnibook 5500},"
"{TerraTec,Maestro 32/96},"
- "{Philips,PCA70PS}}");
-#else
-MODULE_DESCRIPTION("Cirrus Logic CS4235-9");
-MODULE_SUPPORTED_DEVICE("{{Crystal Semiconductors,CS4235},"
+ "{Philips,PCA70PS}},"
+ "{{Crystal Semiconductors,CS4235},"
"{Crystal Semiconductors,CS4236},"
"{Crystal Semiconductors,CS4237},"
"{Crystal Semiconductors,CS4238},"
@@ -70,15 +67,11 @@ MODULE_SUPPORTED_DEVICE("{{Crystal Semiconductors,CS4235},"
"{Typhoon Soundsystem,CS4236B},"
"{Turtle Beach,Malibu},"
"{Unknown,Digital PC 5000 Onboard}}");
-#endif
-#ifdef CS4232
-#define IDENT "CS4232"
-#define DEV_NAME "cs4232"
-#else
-#define IDENT "CS4236+"
-#define DEV_NAME "cs4236"
-#endif
+MODULE_ALIAS("snd_cs4232");
+
+#define IDENT "CS4232+"
+#define DEV_NAME "cs4232+"
static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX; /* Index 0-MAX */
static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR; /* ID for this card */
@@ -128,9 +121,7 @@ MODULE_PARM_DESC(dma2, "DMA2 # for " IDENT " driver.");
#ifdef CONFIG_PNP
static int isa_registered;
static int pnpc_registered;
-#ifdef CS4232
static int pnp_registered;
-#endif
#endif /* CONFIG_PNP */
struct snd_card_cs4236 {
@@ -145,11 +136,10 @@ struct snd_card_cs4236 {
#ifdef CONFIG_PNP
-#ifdef CS4232
/*
* PNP BIOS
*/
-static const struct pnp_device_id snd_cs4232_pnpbiosids[] = {
+static const struct pnp_device_id snd_cs423x_pnpbiosids[] = {
{ .id = "CSC0100" },
{ .id = "CSC0000" },
/* Guillemot Turtlebeach something appears to be cs4232 compatible
@@ -157,10 +147,8 @@ static const struct pnp_device_id snd_cs4232_pnpbiosids[] = {
{ .id = "GIM0100" },
{ .id = "" }
};
-MODULE_DEVICE_TABLE(pnp, snd_cs4232_pnpbiosids);
-#endif /* CS4232 */
+MODULE_DEVICE_TABLE(pnp, snd_cs423x_pnpbiosids);
-#ifdef CS4232
#define CS423X_ISAPNP_DRIVER "cs4232_isapnp"
static struct pnp_card_device_id snd_cs423x_pnpids[] = {
/* Philips PCA70PS */
@@ -179,12 +167,6 @@ static struct pnp_card_device_id snd_cs423x_pnpids[] = {
{ .id = "CSCf032", .devs = { { "CSC0000" }, { "CSC0010" }, { "CSC0003" } } },
/* Netfinity 3000 on-board soundcard */
{ .id = "CSCe825", .devs = { { "CSC0100" }, { "CSC0110" }, { "CSC010f" } } },
- /* --- */
- { .id = "" } /* end */
-};
-#else /* CS4236 */
-#define CS423X_ISAPNP_DRIVER "cs4236_isapnp"
-static struct pnp_card_device_id snd_cs423x_pnpids[] = {
/* Intel Marlin Spike Motherboard - CS4235 */
{ .id = "CSC0225", .devs = { { "CSC0000" }, { "CSC0010" }, { "CSC0003" } } },
/* Intel Marlin Spike Motherboard (#2) - CS4235 */
@@ -266,7 +248,6 @@ static struct pnp_card_device_id snd_cs423x_pnpids[] = {
/* --- */
{ .id = "" } /* end */
};
-#endif
MODULE_DEVICE_TABLE(pnp_card, snd_cs423x_pnpids);
@@ -323,17 +304,19 @@ static int __devinit snd_cs423x_pnp_init_mpu(int dev, struct pnp_dev *pdev)
return 0;
}
-#ifdef CS4232
-static int __devinit snd_card_cs4232_pnp(int dev, struct snd_card_cs4236 *acard,
- struct pnp_dev *pdev)
+static int __devinit snd_card_cs423x_pnp(int dev, struct snd_card_cs4236 *acard,
+ struct pnp_dev *pdev,
+ struct pnp_dev *cdev)
{
acard->wss = pdev;
if (snd_cs423x_pnp_init_wss(dev, acard->wss) < 0)
return -EBUSY;
- cport[dev] = -1;
+ if (cdev)
+ cport[dev] = pnp_port_start(cdev, 0);
+ else
+ cport[dev] = -1;
return 0;
}
-#endif
static int __devinit snd_card_cs423x_pnpc(int dev, struct snd_card_cs4236 *acard,
struct pnp_card_link *card,
@@ -382,16 +365,18 @@ static void snd_card_cs4236_free(struct snd_card *card)
release_and_free_resource(acard->res_sb_port);
}
-static struct snd_card *snd_cs423x_card_new(int dev)
+static int snd_cs423x_card_new(int dev, struct snd_card **cardp)
{
struct snd_card *card;
+ int err;
- card = snd_card_new(index[dev], id[dev], THIS_MODULE,
- sizeof(struct snd_card_cs4236));
- if (card == NULL)
- return NULL;
+ err = snd_card_create(index[dev], id[dev], THIS_MODULE,
+ sizeof(struct snd_card_cs4236), &card);
+ if (err < 0)
+ return err;
card->private_free = snd_card_cs4236_free;
- return card;
+ *cardp = card;
+ return 0;
}
static int __devinit snd_cs423x_probe(struct snd_card *card, int dev)
@@ -409,40 +394,39 @@ static int __devinit snd_cs423x_probe(struct snd_card *card, int dev)
return -EBUSY;
}
-#ifdef CS4232
err = snd_wss_create(card, port[dev], cport[dev],
irq[dev],
dma1[dev], dma2[dev],
- WSS_HW_DETECT, 0, &chip);
- if (err < 0)
- return err;
- acard->chip = chip;
-
- err = snd_wss_pcm(chip, 0, &pcm);
- if (err < 0)
- return err;
-
- err = snd_wss_mixer(chip);
+ WSS_HW_DETECT3, 0, &chip);
if (err < 0)
return err;
-
-#else /* CS4236 */
- err = snd_cs4236_create(card,
- port[dev], cport[dev],
- irq[dev], dma1[dev], dma2[dev],
- WSS_HW_DETECT, 0, &chip);
- if (err < 0)
- return err;
- acard->chip = chip;
-
- err = snd_cs4236_pcm(chip, 0, &pcm);
- if (err < 0)
- return err;
-
- err = snd_cs4236_mixer(chip);
- if (err < 0)
- return err;
-#endif
+ if (chip->hardware & WSS_HW_CS4236B_MASK) {
+ snd_wss_free(chip);
+ err = snd_cs4236_create(card,
+ port[dev], cport[dev],
+ irq[dev], dma1[dev], dma2[dev],
+ WSS_HW_DETECT, 0, &chip);
+ if (err < 0)
+ return err;
+ acard->chip = chip;
+
+ err = snd_cs4236_pcm(chip, 0, &pcm);
+ if (err < 0)
+ return err;
+
+ err = snd_cs4236_mixer(chip);
+ if (err < 0)
+ return err;
+ } else {
+ acard->chip = chip;
+ err = snd_wss_pcm(chip, 0, &pcm);
+ if (err < 0)
+ return err;
+
+ err = snd_wss_mixer(chip);
+ if (err < 0)
+ return err;
+ }
strcpy(card->driver, pcm->name);
strcpy(card->shortname, pcm->name);
sprintf(card->longname, "%s at 0x%lx, irq %i, dma %i",
@@ -512,9 +496,9 @@ static int __devinit snd_cs423x_isa_probe(struct device *pdev,
struct snd_card *card;
int err;
- card = snd_cs423x_card_new(dev);
- if (! card)
- return -ENOMEM;
+ err = snd_cs423x_card_new(dev, &card);
+ if (err < 0)
+ return err;
snd_card_set_dev(card, pdev);
if ((err = snd_cs423x_probe(card, dev)) < 0) {
snd_card_free(card);
@@ -577,13 +561,14 @@ static struct isa_driver cs423x_isa_driver = {
#ifdef CONFIG_PNP
-#ifdef CS4232
-static int __devinit snd_cs4232_pnpbios_detect(struct pnp_dev *pdev,
+static int __devinit snd_cs423x_pnpbios_detect(struct pnp_dev *pdev,
const struct pnp_device_id *id)
{
static int dev;
int err;
struct snd_card *card;
+ struct pnp_dev *cdev;
+ char cid[PNP_ID_LEN];
if (pnp_device_is_isapnp(pdev))
return -ENOENT; /* we have another procedure - card */
@@ -594,10 +579,19 @@ static int __devinit snd_cs4232_pnpbios_detect(struct pnp_dev *pdev,
if (dev >= SNDRV_CARDS)
return -ENODEV;
- card = snd_cs423x_card_new(dev);
- if (! card)
- return -ENOMEM;
- if ((err = snd_card_cs4232_pnp(dev, card->private_data, pdev)) < 0) {
+ /* prepare second id */
+ strcpy(cid, pdev->id[0].id);
+ cid[5] = '1';
+ cdev = NULL;
+ list_for_each_entry(cdev, &(pdev->protocol->devices), protocol_list) {
+ if (!strcmp(cdev->id[0].id, cid))
+ break;
+ }
+ err = snd_cs423x_card_new(dev, &card);
+ if (err < 0)
+ return err;
+ err = snd_card_cs423x_pnp(dev, card->private_data, pdev, cdev);
+ if (err < 0) {
printk(KERN_ERR "PnP BIOS detection failed for " IDENT "\n");
snd_card_free(card);
return err;
@@ -612,35 +606,34 @@ static int __devinit snd_cs4232_pnpbios_detect(struct pnp_dev *pdev,
return 0;
}
-static void __devexit snd_cs4232_pnp_remove(struct pnp_dev * pdev)
+static void __devexit snd_cs423x_pnp_remove(struct pnp_dev *pdev)
{
snd_card_free(pnp_get_drvdata(pdev));
pnp_set_drvdata(pdev, NULL);
}
#ifdef CONFIG_PM
-static int snd_cs4232_pnp_suspend(struct pnp_dev *pdev, pm_message_t state)
+static int snd_cs423x_pnp_suspend(struct pnp_dev *pdev, pm_message_t state)
{
return snd_cs423x_suspend(pnp_get_drvdata(pdev));
}
-static int snd_cs4232_pnp_resume(struct pnp_dev *pdev)
+static int snd_cs423x_pnp_resume(struct pnp_dev *pdev)
{
return snd_cs423x_resume(pnp_get_drvdata(pdev));
}
#endif
-static struct pnp_driver cs4232_pnp_driver = {
- .name = "cs4232-pnpbios",
- .id_table = snd_cs4232_pnpbiosids,
- .probe = snd_cs4232_pnpbios_detect,
- .remove = __devexit_p(snd_cs4232_pnp_remove),
+static struct pnp_driver cs423x_pnp_driver = {
+ .name = "cs423x-pnpbios",
+ .id_table = snd_cs423x_pnpbiosids,
+ .probe = snd_cs423x_pnpbios_detect,
+ .remove = __devexit_p(snd_cs423x_pnp_remove),
#ifdef CONFIG_PM
- .suspend = snd_cs4232_pnp_suspend,
- .resume = snd_cs4232_pnp_resume,
+ .suspend = snd_cs423x_pnp_suspend,
+ .resume = snd_cs423x_pnp_resume,
#endif
};
-#endif /* CS4232 */
static int __devinit snd_cs423x_pnpc_detect(struct pnp_card_link *pcard,
const struct pnp_card_device_id *pid)
@@ -656,9 +649,9 @@ static int __devinit snd_cs423x_pnpc_detect(struct pnp_card_link *pcard,
if (dev >= SNDRV_CARDS)
return -ENODEV;
- card = snd_cs423x_card_new(dev);
- if (! card)
- return -ENOMEM;
+ res = snd_cs423x_card_new(dev, &card);
+ if (res < 0)
+ return res;
if ((res = snd_card_cs423x_pnpc(dev, card->private_data, pcard, pid)) < 0) {
printk(KERN_ERR "isapnp detection failed and probing for " IDENT
" is not supported\n");
@@ -714,18 +707,14 @@ static int __init alsa_card_cs423x_init(void)
#ifdef CONFIG_PNP
if (!err)
isa_registered = 1;
-#ifdef CS4232
- err = pnp_register_driver(&cs4232_pnp_driver);
+ err = pnp_register_driver(&cs423x_pnp_driver);
if (!err)
pnp_registered = 1;
-#endif
err = pnp_register_card_driver(&cs423x_pnpc_driver);
if (!err)
pnpc_registered = 1;
-#ifdef CS4232
if (pnp_registered)
err = 0;
-#endif
if (isa_registered)
err = 0;
#endif
@@ -737,10 +726,8 @@ static void __exit alsa_card_cs423x_exit(void)
#ifdef CONFIG_PNP
if (pnpc_registered)
pnp_unregister_card_driver(&cs423x_pnpc_driver);
-#ifdef CS4232
if (pnp_registered)
- pnp_unregister_driver(&cs4232_pnp_driver);
-#endif
+ pnp_unregister_driver(&cs423x_pnp_driver);
if (isa_registered)
#endif
isa_unregister_driver(&cs423x_isa_driver);
diff --git a/sound/isa/cs423x/cs4236_lib.c b/sound/isa/cs423x/cs4236_lib.c
index 6a85fdc53b6..38835f31298 100644
--- a/sound/isa/cs423x/cs4236_lib.c
+++ b/sound/isa/cs423x/cs4236_lib.c
@@ -88,10 +88,6 @@
#include <sound/wss.h>
#include <sound/asoundef.h>
-MODULE_AUTHOR("Jaroslav Kysela <perex@perex.cz>");
-MODULE_DESCRIPTION("Routines for control of CS4235/4236B/4237B/4238B/4239 chips");
-MODULE_LICENSE("GPL");
-
/*
*
*/
@@ -286,7 +282,8 @@ int snd_cs4236_create(struct snd_card *card,
if (hardware == WSS_HW_DETECT)
hardware = WSS_HW_DETECT3;
if (cport < 0x100) {
- snd_printk("please, specify control port for CS4236+ chips\n");
+ snd_printk(KERN_ERR "please, specify control port "
+ "for CS4236+ chips\n");
return -ENODEV;
}
err = snd_wss_create(card, port, cport,
@@ -295,7 +292,8 @@ int snd_cs4236_create(struct snd_card *card,
return err;
if (!(chip->hardware & WSS_HW_CS4236B_MASK)) {
- snd_printk("CS4236+: MODE3 and extended registers not available, hardware=0x%x\n",chip->hardware);
+ snd_printk(KERN_ERR "CS4236+: MODE3 and extended registers "
+ "not available, hardware=0x%x\n", chip->hardware);
snd_device_free(card, chip);
return -ENODEV;
}
@@ -303,16 +301,19 @@ int snd_cs4236_create(struct snd_card *card,
{
int idx;
for (idx = 0; idx < 8; idx++)
- snd_printk("CD%i = 0x%x\n", idx, inb(chip->cport + idx));
+ snd_printk(KERN_DEBUG "CD%i = 0x%x\n",
+ idx, inb(chip->cport + idx));
for (idx = 0; idx < 9; idx++)
- snd_printk("C%i = 0x%x\n", idx, snd_cs4236_ctrl_in(chip, idx));
+ snd_printk(KERN_DEBUG "C%i = 0x%x\n",
+ idx, snd_cs4236_ctrl_in(chip, idx));
}
#endif
ver1 = snd_cs4236_ctrl_in(chip, 1);
ver2 = snd_cs4236_ext_in(chip, CS4236_VERSION);
snd_printdd("CS4236: [0x%lx] C1 (version) = 0x%x, ext = 0x%x\n", cport, ver1, ver2);
if (ver1 != ver2) {
- snd_printk("CS4236+ chip detected, but control port 0x%lx is not valid\n", cport);
+ snd_printk(KERN_ERR "CS4236+ chip detected, but "
+ "control port 0x%lx is not valid\n", cport);
snd_device_free(card, chip);
return -ENODEV;
}
@@ -883,7 +884,8 @@ static int snd_cs4236_get_iec958_switch(struct snd_kcontrol *kcontrol, struct sn
spin_lock_irqsave(&chip->reg_lock, flags);
ucontrol->value.integer.value[0] = chip->image[CS4231_ALT_FEATURE_1] & 0x02 ? 1 : 0;
#if 0
- printk("get valid: ALT = 0x%x, C3 = 0x%x, C4 = 0x%x, C5 = 0x%x, C6 = 0x%x, C8 = 0x%x\n",
+ printk(KERN_DEBUG "get valid: ALT = 0x%x, C3 = 0x%x, C4 = 0x%x, "
+ "C5 = 0x%x, C6 = 0x%x, C8 = 0x%x\n",
snd_wss_in(chip, CS4231_ALT_FEATURE_1),
snd_cs4236_ctrl_in(chip, 3),
snd_cs4236_ctrl_in(chip, 4),
@@ -920,7 +922,8 @@ static int snd_cs4236_put_iec958_switch(struct snd_kcontrol *kcontrol, struct sn
mutex_unlock(&chip->mce_mutex);
#if 0
- printk("set valid: ALT = 0x%x, C3 = 0x%x, C4 = 0x%x, C5 = 0x%x, C6 = 0x%x, C8 = 0x%x\n",
+ printk(KERN_DEBUG "set valid: ALT = 0x%x, C3 = 0x%x, C4 = 0x%x, "
+ "C5 = 0x%x, C6 = 0x%x, C8 = 0x%x\n",
snd_wss_in(chip, CS4231_ALT_FEATURE_1),
snd_cs4236_ctrl_in(chip, 3),
snd_cs4236_ctrl_in(chip, 4),
@@ -1015,23 +1018,3 @@ int snd_cs4236_mixer(struct snd_wss *chip)
}
return 0;
}
-
-EXPORT_SYMBOL(snd_cs4236_create);
-EXPORT_SYMBOL(snd_cs4236_pcm);
-EXPORT_SYMBOL(snd_cs4236_mixer);
-
-/*
- * INIT part
- */
-
-static int __init alsa_cs4236_init(void)
-{
- return 0;
-}
-
-static void __exit alsa_cs4236_exit(void)
-{
-}
-
-module_init(alsa_cs4236_init)
-module_exit(alsa_cs4236_exit)
diff --git a/sound/isa/dt019x.c b/sound/isa/dt019x.c
index a0242c3b613..80f5b1af9be 100644
--- a/sound/isa/dt019x.c
+++ b/sound/isa/dt019x.c
@@ -150,9 +150,10 @@ static int __devinit snd_card_dt019x_probe(int dev, struct pnp_card_link *pcard,
struct snd_card_dt019x *acard;
struct snd_opl3 *opl3;
- if ((card = snd_card_new(index[dev], id[dev], THIS_MODULE,
- sizeof(struct snd_card_dt019x))) == NULL)
- return -ENOMEM;
+ error = snd_card_create(index[dev], id[dev], THIS_MODULE,
+ sizeof(struct snd_card_dt019x), &card);
+ if (error < 0)
+ return error;
acard = card->private_data;
snd_card_set_dev(card, &pcard->card->dev);
diff --git a/sound/isa/es1688/es1688.c b/sound/isa/es1688/es1688.c
index b46377139cf..442b081cafb 100644
--- a/sound/isa/es1688/es1688.c
+++ b/sound/isa/es1688/es1688.c
@@ -49,6 +49,7 @@ 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; /* Enable this card */
static long port[SNDRV_CARDS] = SNDRV_DEFAULT_PORT; /* 0x220,0x240,0x260 */
+static long fm_port[SNDRV_CARDS] = SNDRV_DEFAULT_PORT; /* Usually 0x388 */
static long mpu_port[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS - 1)] = -1};
static int irq[SNDRV_CARDS] = SNDRV_DEFAULT_IRQ; /* 5,7,9,10 */
static int mpu_irq[SNDRV_CARDS] = SNDRV_DEFAULT_IRQ; /* 5,7,9,10 */
@@ -65,6 +66,8 @@ MODULE_PARM_DESC(port, "Port # for " CRD_NAME " driver.");
module_param_array(mpu_port, long, NULL, 0444);
MODULE_PARM_DESC(mpu_port, "MPU-401 port # for " CRD_NAME " driver.");
module_param_array(irq, int, NULL, 0444);
+module_param_array(fm_port, long, NULL, 0444);
+MODULE_PARM_DESC(fm_port, "FM port # for ES1688 driver.");
MODULE_PARM_DESC(irq, "IRQ # for " CRD_NAME " driver.");
module_param_array(mpu_irq, int, NULL, 0444);
MODULE_PARM_DESC(mpu_irq, "MPU-401 IRQ # for " CRD_NAME " driver.");
@@ -122,9 +125,9 @@ static int __devinit snd_es1688_probe(struct device *dev, unsigned int n)
struct snd_pcm *pcm;
int error;
- card = snd_card_new(index[n], id[n], THIS_MODULE, 0);
- if (!card)
- return -EINVAL;
+ error = snd_card_create(index[n], id[n], THIS_MODULE, 0, &card);
+ if (error < 0)
+ return error;
error = snd_es1688_legacy_create(card, dev, n, &chip);
if (error < 0)
@@ -143,13 +146,19 @@ static int __devinit snd_es1688_probe(struct device *dev, unsigned int n)
sprintf(card->longname, "%s at 0x%lx, irq %i, dma %i", pcm->name,
chip->port, chip->irq, chip->dma8);
- if (snd_opl3_create(card, chip->port, chip->port + 2,
- OPL3_HW_OPL3, 0, &opl3) < 0)
- dev_warn(dev, "opl3 not detected at 0x%lx\n", chip->port);
- else {
- error = snd_opl3_hwdep_new(opl3, 0, 1, NULL);
- if (error < 0)
- goto out;
+ if (fm_port[n] == SNDRV_AUTO_PORT)
+ fm_port[n] = port[n]; /* share the same port */
+
+ if (fm_port[n] > 0) {
+ if (snd_opl3_create(card, fm_port[n], fm_port[n] + 2,
+ OPL3_HW_OPL3, 0, &opl3) < 0)
+ dev_warn(dev,
+ "opl3 not detected at 0x%lx\n", fm_port[n]);
+ else {
+ error = snd_opl3_hwdep_new(opl3, 0, 1, NULL);
+ if (error < 0)
+ goto out;
+ }
}
if (mpu_irq[n] >= 0 && mpu_irq[n] != SNDRV_AUTO_IRQ &&
diff --git a/sound/isa/es1688/es1688_lib.c b/sound/isa/es1688/es1688_lib.c
index 4fbb508a817..4c6e14f87f2 100644
--- a/sound/isa/es1688/es1688_lib.c
+++ b/sound/isa/es1688/es1688_lib.c
@@ -45,7 +45,7 @@ static int snd_es1688_dsp_command(struct snd_es1688 *chip, unsigned char val)
return 1;
}
#ifdef CONFIG_SND_DEBUG
- printk("snd_es1688_dsp_command: timeout (0x%x)\n", val);
+ printk(KERN_DEBUG "snd_es1688_dsp_command: timeout (0x%x)\n", val);
#endif
return 0;
}
@@ -167,13 +167,16 @@ static int snd_es1688_probe(struct snd_es1688 *chip)
hw = ES1688_HW_AUTO;
switch (chip->version & 0xfff0) {
case 0x4880:
- snd_printk("[0x%lx] ESS: AudioDrive ES488 detected, but driver is in another place\n", chip->port);
+ snd_printk(KERN_ERR "[0x%lx] ESS: AudioDrive ES488 detected, "
+ "but driver is in another place\n", chip->port);
return -ENODEV;
case 0x6880:
hw = (chip->version & 0x0f) >= 8 ? ES1688_HW_1688 : ES1688_HW_688;
break;
default:
- snd_printk("[0x%lx] ESS: unknown AudioDrive chip with version 0x%x (Jazz16 soundcard?)\n", chip->port, chip->version);
+ snd_printk(KERN_ERR "[0x%lx] ESS: unknown AudioDrive chip "
+ "with version 0x%x (Jazz16 soundcard?)\n",
+ chip->port, chip->version);
return -ENODEV;
}
@@ -223,7 +226,7 @@ static int snd_es1688_init(struct snd_es1688 * chip, int enable)
}
}
#if 0
- snd_printk("mpu cfg = 0x%x\n", cfg);
+ snd_printk(KERN_DEBUG "mpu cfg = 0x%x\n", cfg);
#endif
spin_lock_irqsave(&chip->reg_lock, flags);
snd_es1688_mixer_write(chip, 0x40, cfg);
@@ -237,7 +240,9 @@ static int snd_es1688_init(struct snd_es1688 * chip, int enable)
cfg = 0xf0; /* enable only DMA counter interrupt */
irq_bits = irqs[chip->irq & 0x0f];
if (irq_bits < 0) {
- snd_printk("[0x%lx] ESS: bad IRQ %d for ES1688 chip!!\n", chip->port, chip->irq);
+ snd_printk(KERN_ERR "[0x%lx] ESS: bad IRQ %d "
+ "for ES1688 chip!!\n",
+ chip->port, chip->irq);
#if 0
irq_bits = 0;
cfg = 0x10;
@@ -250,7 +255,8 @@ static int snd_es1688_init(struct snd_es1688 * chip, int enable)
cfg = 0xf0; /* extended mode DMA enable */
dma = chip->dma8;
if (dma > 3 || dma == 2) {
- snd_printk("[0x%lx] ESS: bad DMA channel %d for ES1688 chip!!\n", chip->port, dma);
+ snd_printk(KERN_ERR "[0x%lx] ESS: bad DMA channel %d "
+ "for ES1688 chip!!\n", chip->port, dma);
#if 0
dma_bits = 0;
cfg = 0x00; /* disable all DMA */
@@ -341,8 +347,9 @@ static int snd_es1688_trigger(struct snd_es1688 *chip, int cmd, unsigned char va
return -EINVAL; /* something is wrong */
}
#if 0
- printk("trigger: val = 0x%x, value = 0x%x\n", val, value);
- printk("trigger: pointer = 0x%x\n", snd_dma_pointer(chip->dma8, chip->dma_size));
+ printk(KERN_DEBUG "trigger: val = 0x%x, value = 0x%x\n", val, value);
+ printk(KERN_DEBUG "trigger: pointer = 0x%x\n",
+ snd_dma_pointer(chip->dma8, chip->dma_size));
#endif
snd_es1688_write(chip, 0xb8, (val & 0xf0) | value);
spin_unlock(&chip->reg_lock);
diff --git a/sound/isa/es18xx.c b/sound/isa/es18xx.c
index 90498e4ca26..8cfbff73a83 100644
--- a/sound/isa/es18xx.c
+++ b/sound/isa/es18xx.c
@@ -2125,10 +2125,10 @@ static int __devinit snd_audiodrive_pnpc(int dev, struct snd_audiodrive *acard,
#define is_isapnp_selected(dev) 0
#endif
-static struct snd_card *snd_es18xx_card_new(int dev)
+static int snd_es18xx_card_new(int dev, struct snd_card **cardp)
{
- return snd_card_new(index[dev], id[dev], THIS_MODULE,
- sizeof(struct snd_audiodrive));
+ return snd_card_create(index[dev], id[dev], THIS_MODULE,
+ sizeof(struct snd_audiodrive), cardp);
}
static int __devinit snd_audiodrive_probe(struct snd_card *card, int dev)
@@ -2197,9 +2197,9 @@ static int __devinit snd_es18xx_isa_probe1(int dev, struct device *devptr)
struct snd_card *card;
int err;
- card = snd_es18xx_card_new(dev);
- if (! card)
- return -ENOMEM;
+ err = snd_es18xx_card_new(dev, &card);
+ if (err < 0)
+ return err;
snd_card_set_dev(card, devptr);
if ((err = snd_audiodrive_probe(card, dev)) < 0) {
snd_card_free(card);
@@ -2303,9 +2303,9 @@ static int __devinit snd_audiodrive_pnp_detect(struct pnp_dev *pdev,
if (dev >= SNDRV_CARDS)
return -ENODEV;
- card = snd_es18xx_card_new(dev);
- if (! card)
- return -ENOMEM;
+ err = snd_es18xx_card_new(dev, &card);
+ if (err < 0)
+ return err;
if ((err = snd_audiodrive_pnp(dev, card->private_data, pdev)) < 0) {
snd_card_free(card);
return err;
@@ -2362,9 +2362,9 @@ static int __devinit snd_audiodrive_pnpc_detect(struct pnp_card_link *pcard,
if (dev >= SNDRV_CARDS)
return -ENODEV;
- card = snd_es18xx_card_new(dev);
- if (! card)
- return -ENOMEM;
+ res = snd_es18xx_card_new(dev, &card);
+ if (res < 0)
+ return res;
if ((res = snd_audiodrive_pnpc(dev, card->private_data, pcard, pid)) < 0) {
snd_card_free(card);
diff --git a/sound/isa/gus/gus_dma.c b/sound/isa/gus/gus_dma.c
index f45f6116c77..36c27c83236 100644
--- a/sound/isa/gus/gus_dma.c
+++ b/sound/isa/gus/gus_dma.c
@@ -45,7 +45,8 @@ static void snd_gf1_dma_program(struct snd_gus_card * gus,
unsigned char dma_cmd;
unsigned int address_high;
- // snd_printk("dma_transfer: addr=0x%x, buf=0x%lx, count=0x%x\n", addr, (long) buf, count);
+ snd_printdd("dma_transfer: addr=0x%x, buf=0x%lx, count=0x%x\n",
+ addr, buf_addr, count);
if (gus->gf1.dma1 > 3) {
if (gus->gf1.enh_mode) {
@@ -77,7 +78,8 @@ static void snd_gf1_dma_program(struct snd_gus_card * gus,
snd_gf1_dma_ack(gus);
snd_dma_program(gus->gf1.dma1, buf_addr, count, dma_cmd & SNDRV_GF1_DMA_READ ? DMA_MODE_READ : DMA_MODE_WRITE);
#if 0
- snd_printk("address = 0x%x, count = 0x%x, dma_cmd = 0x%x\n", address << 1, count, dma_cmd);
+ snd_printk(KERN_DEBUG "address = 0x%x, count = 0x%x, dma_cmd = 0x%x\n",
+ address << 1, count, dma_cmd);
#endif
spin_lock_irqsave(&gus->reg_lock, flags);
if (gus->gf1.enh_mode) {
@@ -142,7 +144,9 @@ static void snd_gf1_dma_interrupt(struct snd_gus_card * gus)
snd_gf1_dma_program(gus, block->addr, block->buf_addr, block->count, (unsigned short) block->cmd);
kfree(block);
#if 0
- printk("program dma (IRQ) - addr = 0x%x, buffer = 0x%lx, count = 0x%x, cmd = 0x%x\n", addr, (long) buffer, count, cmd);
+ snd_printd(KERN_DEBUG "program dma (IRQ) - "
+ "addr = 0x%x, buffer = 0x%lx, count = 0x%x, cmd = 0x%x\n",
+ block->addr, block->buf_addr, block->count, block->cmd);
#endif
}
@@ -203,13 +207,16 @@ int snd_gf1_dma_transfer_block(struct snd_gus_card * gus,
}
*block = *__block;
block->next = NULL;
-#if 0
- printk("addr = 0x%x, buffer = 0x%lx, count = 0x%x, cmd = 0x%x\n", block->addr, (long) block->buffer, block->count, block->cmd);
-#endif
-#if 0
- printk("gus->gf1.dma_data_pcm_last = 0x%lx\n", (long)gus->gf1.dma_data_pcm_last);
- printk("gus->gf1.dma_data_pcm = 0x%lx\n", (long)gus->gf1.dma_data_pcm);
-#endif
+
+ snd_printdd("addr = 0x%x, buffer = 0x%lx, count = 0x%x, cmd = 0x%x\n",
+ block->addr, (long) block->buffer, block->count,
+ block->cmd);
+
+ snd_printdd("gus->gf1.dma_data_pcm_last = 0x%lx\n",
+ (long)gus->gf1.dma_data_pcm_last);
+ snd_printdd("gus->gf1.dma_data_pcm = 0x%lx\n",
+ (long)gus->gf1.dma_data_pcm);
+
spin_lock_irqsave(&gus->dma_lock, flags);
if (synth) {
if (gus->gf1.dma_data_synth_last) {
diff --git a/sound/isa/gus/gus_irq.c b/sound/isa/gus/gus_irq.c
index 041894ddd01..2055aff71b5 100644
--- a/sound/isa/gus/gus_irq.c
+++ b/sound/isa/gus/gus_irq.c
@@ -41,7 +41,7 @@ __again:
if (status == 0)
return IRQ_RETVAL(handled);
handled = 1;
- // snd_printk("IRQ: status = 0x%x\n", status);
+ /* snd_printk(KERN_DEBUG "IRQ: status = 0x%x\n", status); */
if (status & 0x02) {
STAT_ADD(gus->gf1.interrupt_stat_midi_in);
if (gus->gf1.interrupt_handler_midi_in)
@@ -65,7 +65,9 @@ __again:
continue; /* multi request */
already |= _current_; /* mark request */
#if 0
- printk("voice = %i, voice_status = 0x%x, voice_verify = %i\n", voice, voice_status, inb(GUSP(gus, GF1PAGE)));
+ printk(KERN_DEBUG "voice = %i, voice_status = 0x%x, "
+ "voice_verify = %i\n",
+ voice, voice_status, inb(GUSP(gus, GF1PAGE)));
#endif
pvoice = &gus->gf1.voices[voice];
if (pvoice->use) {
diff --git a/sound/isa/gus/gus_pcm.c b/sound/isa/gus/gus_pcm.c
index 38510aeb21c..edb11eefdfe 100644
--- a/sound/isa/gus/gus_pcm.c
+++ b/sound/isa/gus/gus_pcm.c
@@ -82,7 +82,10 @@ static int snd_gf1_pcm_block_change(struct snd_pcm_substream *substream,
count += offset & 31;
offset &= ~31;
- // snd_printk("block change - offset = 0x%x, count = 0x%x\n", offset, count);
+ /*
+ snd_printk(KERN_DEBUG "block change - offset = 0x%x, count = 0x%x\n",
+ offset, count);
+ */
memset(&block, 0, sizeof(block));
block.cmd = SNDRV_GF1_DMA_IRQ;
if (snd_pcm_format_unsigned(runtime->format))
@@ -135,7 +138,11 @@ static void snd_gf1_pcm_trigger_up(struct snd_pcm_substream *substream)
curr = begin + (pcmp->bpos * pcmp->block_size) / runtime->channels;
end = curr + (pcmp->block_size / runtime->channels);
end -= snd_pcm_format_width(runtime->format) == 16 ? 2 : 1;
- // snd_printk("init: curr=0x%x, begin=0x%x, end=0x%x, ctrl=0x%x, ramp=0x%x, rate=0x%x\n", curr, begin, end, voice_ctrl, ramp_ctrl, rate);
+ /*
+ snd_printk(KERN_DEBUG "init: curr=0x%x, begin=0x%x, end=0x%x, "
+ "ctrl=0x%x, ramp=0x%x, rate=0x%x\n",
+ curr, begin, end, voice_ctrl, ramp_ctrl, rate);
+ */
pan = runtime->channels == 2 ? (!voice ? 1 : 14) : 8;
vol = !voice ? gus->gf1.pcm_volume_level_left : gus->gf1.pcm_volume_level_right;
spin_lock_irqsave(&gus->reg_lock, flags);
@@ -205,9 +212,11 @@ static void snd_gf1_pcm_interrupt_wave(struct snd_gus_card * gus,
ramp_ctrl = (snd_gf1_read8(gus, SNDRV_GF1_VB_VOLUME_CONTROL) & ~0xa4) | 0x03;
#if 0
snd_gf1_select_voice(gus, pvoice->number);
- printk("position = 0x%x\n", (snd_gf1_read_addr(gus, SNDRV_GF1_VA_CURRENT, voice_ctrl & 4) >> 4));
+ printk(KERN_DEBUG "position = 0x%x\n",
+ (snd_gf1_read_addr(gus, SNDRV_GF1_VA_CURRENT, voice_ctrl & 4) >> 4));
snd_gf1_select_voice(gus, pcmp->pvoices[1]->number);
- printk("position = 0x%x\n", (snd_gf1_read_addr(gus, SNDRV_GF1_VA_CURRENT, voice_ctrl & 4) >> 4));
+ printk(KERN_DEBUG "position = 0x%x\n",
+ (snd_gf1_read_addr(gus, SNDRV_GF1_VA_CURRENT, voice_ctrl & 4) >> 4));
snd_gf1_select_voice(gus, pvoice->number);
#endif
pcmp->bpos++;
@@ -299,7 +308,11 @@ static int snd_gf1_pcm_poke_block(struct snd_gus_card *gus, unsigned char *buf,
unsigned int len;
unsigned long flags;
- // printk("poke block; buf = 0x%x, pos = %i, count = %i, port = 0x%x\n", (int)buf, pos, count, gus->gf1.port);
+ /*
+ printk(KERN_DEBUG
+ "poke block; buf = 0x%x, pos = %i, count = %i, port = 0x%x\n",
+ (int)buf, pos, count, gus->gf1.port);
+ */
while (count > 0) {
len = count;
if (len > 512) /* limit, to allow IRQ */
@@ -680,7 +693,8 @@ static int snd_gf1_pcm_playback_open(struct snd_pcm_substream *substream)
runtime->private_free = snd_gf1_pcm_playback_free;
#if 0
- printk("playback.buffer = 0x%lx, gf1.pcm_buffer = 0x%lx\n", (long) pcm->playback.buffer, (long) gus->gf1.pcm_buffer);
+ printk(KERN_DEBUG "playback.buffer = 0x%lx, gf1.pcm_buffer = 0x%lx\n",
+ (long) pcm->playback.buffer, (long) gus->gf1.pcm_buffer);
#endif
if ((err = snd_gf1_dma_init(gus)) < 0)
return err;
diff --git a/sound/isa/gus/gus_uart.c b/sound/isa/gus/gus_uart.c
index f0af3f79b08..21cc42e4c4b 100644
--- a/sound/isa/gus/gus_uart.c
+++ b/sound/isa/gus/gus_uart.c
@@ -129,8 +129,14 @@ static int snd_gf1_uart_input_open(struct snd_rawmidi_substream *substream)
}
spin_unlock_irqrestore(&gus->uart_cmd_lock, flags);
#if 0
- snd_printk("read init - enable = %i, cmd = 0x%x, stat = 0x%x\n", gus->uart_enable, gus->gf1.uart_cmd, snd_gf1_uart_stat(gus));
- snd_printk("[0x%x] reg (ctrl/status) = 0x%x, reg (data) = 0x%x (page = 0x%x)\n", gus->gf1.port + 0x100, inb(gus->gf1.port + 0x100), inb(gus->gf1.port + 0x101), inb(gus->gf1.port + 0x102));
+ snd_printk(KERN_DEBUG
+ "read init - enable = %i, cmd = 0x%x, stat = 0x%x\n",
+ gus->uart_enable, gus->gf1.uart_cmd, snd_gf1_uart_stat(gus));
+ snd_printk(KERN_DEBUG
+ "[0x%x] reg (ctrl/status) = 0x%x, reg (data) = 0x%x "
+ "(page = 0x%x)\n",
+ gus->gf1.port + 0x100, inb(gus->gf1.port + 0x100),
+ inb(gus->gf1.port + 0x101), inb(gus->gf1.port + 0x102));
#endif
return 0;
}
diff --git a/sound/isa/gus/gusclassic.c b/sound/isa/gus/gusclassic.c
index 426532a4d73..086b8f0e0f9 100644
--- a/sound/isa/gus/gusclassic.c
+++ b/sound/isa/gus/gusclassic.c
@@ -148,9 +148,9 @@ static int __devinit snd_gusclassic_probe(struct device *dev, unsigned int n)
struct snd_gus_card *gus;
int error;
- card = snd_card_new(index[n], id[n], THIS_MODULE, 0);
- if (!card)
- return -EINVAL;
+ error = snd_card_create(index[n], id[n], THIS_MODULE, 0, &card);
+ if (error < 0)
+ return error;
if (pcm_channels[n] < 2)
pcm_channels[n] = 2;
diff --git a/sound/isa/gus/gusextreme.c b/sound/isa/gus/gusextreme.c
index 7ad4c3b41a8..180a8dea6bd 100644
--- a/sound/isa/gus/gusextreme.c
+++ b/sound/isa/gus/gusextreme.c
@@ -241,9 +241,9 @@ static int __devinit snd_gusextreme_probe(struct device *dev, unsigned int n)
struct snd_opl3 *opl3;
int error;
- card = snd_card_new(index[n], id[n], THIS_MODULE, 0);
- if (!card)
- return -EINVAL;
+ error = snd_card_create(index[n], id[n], THIS_MODULE, 0, &card);
+ if (error < 0)
+ return error;
if (mpu_port[n] == SNDRV_AUTO_PORT)
mpu_port[n] = 0;
diff --git a/sound/isa/gus/gusmax.c b/sound/isa/gus/gusmax.c
index f94c1976e63..f26eac8d811 100644
--- a/sound/isa/gus/gusmax.c
+++ b/sound/isa/gus/gusmax.c
@@ -214,10 +214,10 @@ static int __devinit snd_gusmax_probe(struct device *pdev, unsigned int dev)
struct snd_wss *wss;
struct snd_gusmax *maxcard;
- card = snd_card_new(index[dev], id[dev], THIS_MODULE,
- sizeof(struct snd_gusmax));
- if (card == NULL)
- return -ENOMEM;
+ err = snd_card_create(index[dev], id[dev], THIS_MODULE,
+ sizeof(struct snd_gusmax), &card);
+ if (err < 0)
+ return err;
card->private_free = snd_gusmax_free;
maxcard = (struct snd_gusmax *)card->private_data;
maxcard->card = card;
diff --git a/sound/isa/gus/interwave.c b/sound/isa/gus/interwave.c
index 5faecfb602d..534a6eced2b 100644
--- a/sound/isa/gus/interwave.c
+++ b/sound/isa/gus/interwave.c
@@ -170,7 +170,7 @@ static void snd_interwave_i2c_setlines(struct snd_i2c_bus *bus, int ctrl, int da
unsigned long port = bus->private_value;
#if 0
- printk("i2c_setlines - 0x%lx <- %i,%i\n", port, ctrl, data);
+ printk(KERN_DEBUG "i2c_setlines - 0x%lx <- %i,%i\n", port, ctrl, data);
#endif
outb((data << 1) | ctrl, port);
udelay(10);
@@ -183,7 +183,7 @@ static int snd_interwave_i2c_getclockline(struct snd_i2c_bus *bus)
res = inb(port) & 1;
#if 0
- printk("i2c_getclockline - 0x%lx -> %i\n", port, res);
+ printk(KERN_DEBUG "i2c_getclockline - 0x%lx -> %i\n", port, res);
#endif
return res;
}
@@ -197,7 +197,7 @@ static int snd_interwave_i2c_getdataline(struct snd_i2c_bus *bus, int ack)
udelay(10);
res = (inb(port) & 2) >> 1;
#if 0
- printk("i2c_getdataline - 0x%lx -> %i\n", port, res);
+ printk(KERN_DEBUG "i2c_getdataline - 0x%lx -> %i\n", port, res);
#endif
return res;
}
@@ -342,7 +342,8 @@ static void __devinit snd_interwave_bank_sizes(struct snd_gus_card * gus, int *s
snd_gf1_poke(gus, local, d);
snd_gf1_poke(gus, local + 1, d + 1);
#if 0
- printk("d = 0x%x, local = 0x%x, local + 1 = 0x%x, idx << 22 = 0x%x\n",
+ printk(KERN_DEBUG "d = 0x%x, local = 0x%x, "
+ "local + 1 = 0x%x, idx << 22 = 0x%x\n",
d,
snd_gf1_peek(gus, local),
snd_gf1_peek(gus, local + 1),
@@ -356,7 +357,8 @@ static void __devinit snd_interwave_bank_sizes(struct snd_gus_card * gus, int *s
}
}
#if 0
- printk("sizes: %i %i %i %i\n", sizes[0], sizes[1], sizes[2], sizes[3]);
+ printk(KERN_DEBUG "sizes: %i %i %i %i\n",
+ sizes[0], sizes[1], sizes[2], sizes[3]);
#endif
}
@@ -410,12 +412,12 @@ static void __devinit snd_interwave_detect_memory(struct snd_gus_card * gus)
lmct = (psizes[3] << 24) | (psizes[2] << 16) |
(psizes[1] << 8) | psizes[0];
#if 0
- printk("lmct = 0x%08x\n", lmct);
+ printk(KERN_DEBUG "lmct = 0x%08x\n", lmct);
#endif
for (i = 0; i < ARRAY_SIZE(lmc); i++)
if (lmct == lmc[i]) {
#if 0
- printk("found !!! %i\n", i);
+ printk(KERN_DEBUG "found !!! %i\n", i);
#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);
@@ -626,20 +628,22 @@ static void snd_interwave_free(struct snd_card *card)
free_irq(iwcard->irq, (void *)iwcard);
}
-static struct snd_card *snd_interwave_card_new(int dev)
+static int snd_interwave_card_new(int dev, struct snd_card **cardp)
{
struct snd_card *card;
struct snd_interwave *iwcard;
+ int err;
- card = snd_card_new(index[dev], id[dev], THIS_MODULE,
- sizeof(struct snd_interwave));
- if (card == NULL)
- return NULL;
+ err = snd_card_create(index[dev], id[dev], THIS_MODULE,
+ sizeof(struct snd_interwave), &card);
+ if (err < 0)
+ return err;
iwcard = card->private_data;
iwcard->card = card;
iwcard->irq = -1;
card->private_free = snd_interwave_free;
- return card;
+ *cardp = card;
+ return 0;
}
static int __devinit snd_interwave_probe(struct snd_card *card, int dev)
@@ -778,9 +782,9 @@ static int __devinit snd_interwave_isa_probe1(int dev, struct device *devptr)
struct snd_card *card;
int err;
- card = snd_interwave_card_new(dev);
- if (! card)
- return -ENOMEM;
+ err = snd_interwave_card_new(dev, &card);
+ if (err < 0)
+ return err;
snd_card_set_dev(card, devptr);
if ((err = snd_interwave_probe(card, dev)) < 0) {
@@ -876,9 +880,9 @@ static int __devinit snd_interwave_pnp_detect(struct pnp_card_link *pcard,
if (dev >= SNDRV_CARDS)
return -ENODEV;
- card = snd_interwave_card_new(dev);
- if (! card)
- return -ENOMEM;
+ res = snd_interwave_card_new(dev, &card);
+ if (res < 0)
+ return res;
if ((res = snd_interwave_pnp(dev, card->private_data, pcard, pid)) < 0) {
snd_card_free(card);
diff --git a/sound/isa/msnd/Makefile b/sound/isa/msnd/Makefile
new file mode 100644
index 00000000000..2171c0aa2f6
--- /dev/null
+++ b/sound/isa/msnd/Makefile
@@ -0,0 +1,9 @@
+
+snd-msnd-lib-objs := msnd.o msnd_midi.o msnd_pinnacle_mixer.o
+snd-msnd-pinnacle-objs := msnd_pinnacle.o
+snd-msnd-classic-objs := msnd_classic.o
+
+# Toplevel Module Dependency
+obj-$(CONFIG_SND_MSND_PINNACLE) += snd-msnd-pinnacle.o snd-msnd-lib.o
+obj-$(CONFIG_SND_MSND_CLASSIC) += snd-msnd-classic.o snd-msnd-lib.o
+
diff --git a/sound/isa/msnd/msnd.c b/sound/isa/msnd/msnd.c
new file mode 100644
index 00000000000..906454413ed
--- /dev/null
+++ b/sound/isa/msnd/msnd.c
@@ -0,0 +1,705 @@
+/*********************************************************************
+ *
+ * 2002/06/30 Karsten Wiese:
+ * removed kernel-version dependencies.
+ * ripped from linux kernel 2.4.18 (OSS Implementation) by me.
+ * In the OSS Version, this file is compiled to a separate MODULE,
+ * that is used by the pinnacle and the classic driver.
+ * since there is no classic driver for alsa yet (i dont have a classic
+ * & writing one blindfold is difficult) this file's object is statically
+ * linked into the pinnacle-driver-module for now. look for the string
+ * "uncomment this to make this a module again"
+ * to do guess what.
+ *
+ * the following is a copy of the 2.4.18 OSS FREE file-heading comment:
+ *
+ * msnd.c - Driver Base
+ *
+ * Turtle Beach MultiSound Sound Card Driver for Linux
+ *
+ * Copyright (C) 1998 Andrew Veliath
+ *
+ * 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ ********************************************************************/
+
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/fs.h>
+#include <linux/delay.h>
+
+#include <sound/core.h>
+#include <sound/initval.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+
+#include "msnd.h"
+
+#define LOGNAME "msnd"
+
+
+void snd_msnd_init_queue(void *base, int start, int size)
+{
+ writew(PCTODSP_BASED(start), base + JQS_wStart);
+ writew(PCTODSP_OFFSET(size) - 1, base + JQS_wSize);
+ writew(0, base + JQS_wHead);
+ writew(0, base + JQS_wTail);
+}
+EXPORT_SYMBOL(snd_msnd_init_queue);
+
+static int snd_msnd_wait_TXDE(struct snd_msnd *dev)
+{
+ unsigned int io = dev->io;
+ int timeout = 1000;
+
+ while (timeout-- > 0)
+ if (inb(io + HP_ISR) & HPISR_TXDE)
+ return 0;
+
+ return -EIO;
+}
+
+static int snd_msnd_wait_HC0(struct snd_msnd *dev)
+{
+ unsigned int io = dev->io;
+ int timeout = 1000;
+
+ while (timeout-- > 0)
+ if (!(inb(io + HP_CVR) & HPCVR_HC))
+ return 0;
+
+ return -EIO;
+}
+
+int snd_msnd_send_dsp_cmd(struct snd_msnd *dev, u8 cmd)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&dev->lock, flags);
+ if (snd_msnd_wait_HC0(dev) == 0) {
+ outb(cmd, dev->io + HP_CVR);
+ spin_unlock_irqrestore(&dev->lock, flags);
+ return 0;
+ }
+ spin_unlock_irqrestore(&dev->lock, flags);
+
+ snd_printd(KERN_ERR LOGNAME ": Send DSP command timeout\n");
+
+ return -EIO;
+}
+EXPORT_SYMBOL(snd_msnd_send_dsp_cmd);
+
+int snd_msnd_send_word(struct snd_msnd *dev, unsigned char high,
+ unsigned char mid, unsigned char low)
+{
+ unsigned int io = dev->io;
+
+ if (snd_msnd_wait_TXDE(dev) == 0) {
+ outb(high, io + HP_TXH);
+ outb(mid, io + HP_TXM);
+ outb(low, io + HP_TXL);
+ return 0;
+ }
+
+ snd_printd(KERN_ERR LOGNAME ": Send host word timeout\n");
+
+ return -EIO;
+}
+EXPORT_SYMBOL(snd_msnd_send_word);
+
+int snd_msnd_upload_host(struct snd_msnd *dev, const u8 *bin, int len)
+{
+ int i;
+
+ if (len % 3 != 0) {
+ snd_printk(KERN_ERR LOGNAME
+ ": Upload host data not multiple of 3!\n");
+ return -EINVAL;
+ }
+
+ for (i = 0; i < len; i += 3)
+ if (snd_msnd_send_word(dev, bin[i], bin[i + 1], bin[i + 2]))
+ return -EIO;
+
+ inb(dev->io + HP_RXL);
+ inb(dev->io + HP_CVR);
+
+ return 0;
+}
+EXPORT_SYMBOL(snd_msnd_upload_host);
+
+int snd_msnd_enable_irq(struct snd_msnd *dev)
+{
+ unsigned long flags;
+
+ if (dev->irq_ref++)
+ return 0;
+
+ snd_printdd(LOGNAME ": Enabling IRQ\n");
+
+ spin_lock_irqsave(&dev->lock, flags);
+ if (snd_msnd_wait_TXDE(dev) == 0) {
+ outb(inb(dev->io + HP_ICR) | HPICR_TREQ, dev->io + HP_ICR);
+ if (dev->type == msndClassic)
+ outb(dev->irqid, dev->io + HP_IRQM);
+
+ outb(inb(dev->io + HP_ICR) & ~HPICR_TREQ, dev->io + HP_ICR);
+ outb(inb(dev->io + HP_ICR) | HPICR_RREQ, dev->io + HP_ICR);
+ enable_irq(dev->irq);
+ snd_msnd_init_queue(dev->DSPQ, dev->dspq_data_buff,
+ dev->dspq_buff_size);
+ spin_unlock_irqrestore(&dev->lock, flags);
+ return 0;
+ }
+ spin_unlock_irqrestore(&dev->lock, flags);
+
+ snd_printd(KERN_ERR LOGNAME ": Enable IRQ failed\n");
+
+ return -EIO;
+}
+EXPORT_SYMBOL(snd_msnd_enable_irq);
+
+int snd_msnd_disable_irq(struct snd_msnd *dev)
+{
+ unsigned long flags;
+
+ if (--dev->irq_ref > 0)
+ return 0;
+
+ if (dev->irq_ref < 0)
+ snd_printd(KERN_WARNING LOGNAME ": IRQ ref count is %d\n",
+ dev->irq_ref);
+
+ snd_printdd(LOGNAME ": Disabling IRQ\n");
+
+ spin_lock_irqsave(&dev->lock, flags);
+ if (snd_msnd_wait_TXDE(dev) == 0) {
+ outb(inb(dev->io + HP_ICR) & ~HPICR_RREQ, dev->io + HP_ICR);
+ if (dev->type == msndClassic)
+ outb(HPIRQ_NONE, dev->io + HP_IRQM);
+ disable_irq(dev->irq);
+ spin_unlock_irqrestore(&dev->lock, flags);
+ return 0;
+ }
+ spin_unlock_irqrestore(&dev->lock, flags);
+
+ snd_printd(KERN_ERR LOGNAME ": Disable IRQ failed\n");
+
+ return -EIO;
+}
+EXPORT_SYMBOL(snd_msnd_disable_irq);
+
+static inline long get_play_delay_jiffies(struct snd_msnd *chip, long size)
+{
+ long tmp = (size * HZ * chip->play_sample_size) / 8;
+ return tmp / (chip->play_sample_rate * chip->play_channels);
+}
+
+static void snd_msnd_dsp_write_flush(struct snd_msnd *chip)
+{
+ if (!(chip->mode & FMODE_WRITE) || !test_bit(F_WRITING, &chip->flags))
+ return;
+ set_bit(F_WRITEFLUSH, &chip->flags);
+/* interruptible_sleep_on_timeout(
+ &chip->writeflush,
+ get_play_delay_jiffies(&chip, chip->DAPF.len));*/
+ clear_bit(F_WRITEFLUSH, &chip->flags);
+ if (!signal_pending(current))
+ schedule_timeout_interruptible(
+ get_play_delay_jiffies(chip, chip->play_period_bytes));
+ clear_bit(F_WRITING, &chip->flags);
+}
+
+void snd_msnd_dsp_halt(struct snd_msnd *chip, struct file *file)
+{
+ if ((file ? file->f_mode : chip->mode) & FMODE_READ) {
+ clear_bit(F_READING, &chip->flags);
+ snd_msnd_send_dsp_cmd(chip, HDEX_RECORD_STOP);
+ snd_msnd_disable_irq(chip);
+ if (file) {
+ snd_printd(KERN_INFO LOGNAME
+ ": Stopping read for %p\n", file);
+ chip->mode &= ~FMODE_READ;
+ }
+ clear_bit(F_AUDIO_READ_INUSE, &chip->flags);
+ }
+ if ((file ? file->f_mode : chip->mode) & FMODE_WRITE) {
+ if (test_bit(F_WRITING, &chip->flags)) {
+ snd_msnd_dsp_write_flush(chip);
+ snd_msnd_send_dsp_cmd(chip, HDEX_PLAY_STOP);
+ }
+ snd_msnd_disable_irq(chip);
+ if (file) {
+ snd_printd(KERN_INFO
+ LOGNAME ": Stopping write for %p\n", file);
+ chip->mode &= ~FMODE_WRITE;
+ }
+ clear_bit(F_AUDIO_WRITE_INUSE, &chip->flags);
+ }
+}
+EXPORT_SYMBOL(snd_msnd_dsp_halt);
+
+
+int snd_msnd_DARQ(struct snd_msnd *chip, int bank)
+{
+ int /*size, n,*/ timeout = 3;
+ u16 wTmp;
+ /* void *DAQD; */
+
+ /* Increment the tail and check for queue wrap */
+ wTmp = readw(chip->DARQ + JQS_wTail) + PCTODSP_OFFSET(DAQDS__size);
+ if (wTmp > readw(chip->DARQ + JQS_wSize))
+ wTmp = 0;
+ while (wTmp == readw(chip->DARQ + JQS_wHead) && timeout--)
+ udelay(1);
+
+ if (chip->capturePeriods == 2) {
+ void *pDAQ = chip->mappedbase + DARQ_DATA_BUFF +
+ bank * DAQDS__size + DAQDS_wStart;
+ unsigned short offset = 0x3000 + chip->capturePeriodBytes;
+
+ if (readw(pDAQ) != PCTODSP_BASED(0x3000))
+ offset = 0x3000;
+ writew(PCTODSP_BASED(offset), pDAQ);
+ }
+
+ writew(wTmp, chip->DARQ + JQS_wTail);
+
+#if 0
+ /* Get our digital audio queue struct */
+ DAQD = bank * DAQDS__size + chip->mappedbase + DARQ_DATA_BUFF;
+
+ /* Get length of data */
+ size = readw(DAQD + DAQDS_wSize);
+
+ /* Read data from the head (unprotected bank 1 access okay
+ since this is only called inside an interrupt) */
+ outb(HPBLKSEL_1, chip->io + HP_BLKS);
+ n = msnd_fifo_write(&chip->DARF,
+ (char *)(chip->base + bank * DAR_BUFF_SIZE),
+ size, 0);
+ if (n <= 0) {
+ outb(HPBLKSEL_0, chip->io + HP_BLKS);
+ return n;
+ }
+ outb(HPBLKSEL_0, chip->io + HP_BLKS);
+#endif
+
+ return 1;
+}
+EXPORT_SYMBOL(snd_msnd_DARQ);
+
+int snd_msnd_DAPQ(struct snd_msnd *chip, int start)
+{
+ u16 DAPQ_tail;
+ int protect = start, nbanks = 0;
+ void *DAQD;
+ static int play_banks_submitted;
+ /* unsigned long flags;
+ spin_lock_irqsave(&chip->lock, flags); not necessary */
+
+ DAPQ_tail = readw(chip->DAPQ + JQS_wTail);
+ while (DAPQ_tail != readw(chip->DAPQ + JQS_wHead) || start) {
+ int bank_num = DAPQ_tail / PCTODSP_OFFSET(DAQDS__size);
+
+ if (start) {
+ start = 0;
+ play_banks_submitted = 0;
+ }
+
+ /* Get our digital audio queue struct */
+ DAQD = bank_num * DAQDS__size + chip->mappedbase +
+ DAPQ_DATA_BUFF;
+
+ /* Write size of this bank */
+ writew(chip->play_period_bytes, DAQD + DAQDS_wSize);
+ if (play_banks_submitted < 3)
+ ++play_banks_submitted;
+ else if (chip->playPeriods == 2) {
+ unsigned short offset = chip->play_period_bytes;
+
+ if (readw(DAQD + DAQDS_wStart) != PCTODSP_BASED(0x0))
+ offset = 0;
+
+ writew(PCTODSP_BASED(offset), DAQD + DAQDS_wStart);
+ }
+ ++nbanks;
+
+ /* Then advance the tail */
+ /*
+ if (protect)
+ snd_printd(KERN_INFO "B %X %lX\n",
+ bank_num, xtime.tv_usec);
+ */
+
+ DAPQ_tail = (++bank_num % 3) * PCTODSP_OFFSET(DAQDS__size);
+ writew(DAPQ_tail, chip->DAPQ + JQS_wTail);
+ /* Tell the DSP to play the bank */
+ snd_msnd_send_dsp_cmd(chip, HDEX_PLAY_START);
+ if (protect)
+ if (2 == bank_num)
+ break;
+ }
+ /*
+ if (protect)
+ snd_printd(KERN_INFO "%lX\n", xtime.tv_usec);
+ */
+ /* spin_unlock_irqrestore(&chip->lock, flags); not necessary */
+ return nbanks;
+}
+EXPORT_SYMBOL(snd_msnd_DAPQ);
+
+static void snd_msnd_play_reset_queue(struct snd_msnd *chip,
+ unsigned int pcm_periods,
+ unsigned int pcm_count)
+{
+ int n;
+ void *pDAQ = chip->mappedbase + DAPQ_DATA_BUFF;
+
+ chip->last_playbank = -1;
+ chip->playLimit = pcm_count * (pcm_periods - 1);
+ chip->playPeriods = pcm_periods;
+ writew(PCTODSP_OFFSET(0 * DAQDS__size), chip->DAPQ + JQS_wHead);
+ writew(PCTODSP_OFFSET(0 * DAQDS__size), chip->DAPQ + JQS_wTail);
+
+ chip->play_period_bytes = pcm_count;
+
+ for (n = 0; n < pcm_periods; ++n, pDAQ += DAQDS__size) {
+ writew(PCTODSP_BASED((u32)(pcm_count * n)),
+ pDAQ + DAQDS_wStart);
+ writew(0, pDAQ + DAQDS_wSize);
+ writew(1, pDAQ + DAQDS_wFormat);
+ writew(chip->play_sample_size, pDAQ + DAQDS_wSampleSize);
+ writew(chip->play_channels, pDAQ + DAQDS_wChannels);
+ writew(chip->play_sample_rate, pDAQ + DAQDS_wSampleRate);
+ writew(HIMT_PLAY_DONE * 0x100 + n, pDAQ + DAQDS_wIntMsg);
+ writew(n, pDAQ + DAQDS_wFlags);
+ }
+}
+
+static void snd_msnd_capture_reset_queue(struct snd_msnd *chip,
+ unsigned int pcm_periods,
+ unsigned int pcm_count)
+{
+ int n;
+ void *pDAQ;
+ /* unsigned long flags; */
+
+ /* snd_msnd_init_queue(chip->DARQ, DARQ_DATA_BUFF, DARQ_BUFF_SIZE); */
+
+ chip->last_recbank = 2;
+ chip->captureLimit = pcm_count * (pcm_periods - 1);
+ chip->capturePeriods = pcm_periods;
+ writew(PCTODSP_OFFSET(0 * DAQDS__size), chip->DARQ + JQS_wHead);
+ writew(PCTODSP_OFFSET(chip->last_recbank * DAQDS__size),
+ chip->DARQ + JQS_wTail);
+
+#if 0 /* Critical section: bank 1 access. this is how the OSS driver does it:*/
+ spin_lock_irqsave(&chip->lock, flags);
+ outb(HPBLKSEL_1, chip->io + HP_BLKS);
+ memset_io(chip->mappedbase, 0, DAR_BUFF_SIZE * 3);
+ outb(HPBLKSEL_0, chip->io + HP_BLKS);
+ spin_unlock_irqrestore(&chip->lock, flags);
+#endif
+
+ chip->capturePeriodBytes = pcm_count;
+ snd_printdd("snd_msnd_capture_reset_queue() %i\n", pcm_count);
+
+ pDAQ = chip->mappedbase + DARQ_DATA_BUFF;
+
+ for (n = 0; n < pcm_periods; ++n, pDAQ += DAQDS__size) {
+ u32 tmp = pcm_count * n;
+
+ writew(PCTODSP_BASED(tmp + 0x3000), pDAQ + DAQDS_wStart);
+ writew(pcm_count, pDAQ + DAQDS_wSize);
+ writew(1, pDAQ + DAQDS_wFormat);
+ writew(chip->capture_sample_size, pDAQ + DAQDS_wSampleSize);
+ writew(chip->capture_channels, pDAQ + DAQDS_wChannels);
+ writew(chip->capture_sample_rate, pDAQ + DAQDS_wSampleRate);
+ writew(HIMT_RECORD_DONE * 0x100 + n, pDAQ + DAQDS_wIntMsg);
+ writew(n, pDAQ + DAQDS_wFlags);
+ }
+}
+
+static struct snd_pcm_hardware snd_msnd_playback = {
+ .info = SNDRV_PCM_INFO_MMAP |
+ SNDRV_PCM_INFO_INTERLEAVED |
+ SNDRV_PCM_INFO_MMAP_VALID,
+ .formats = SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S16_LE,
+ .rates = SNDRV_PCM_RATE_8000_48000,
+ .rate_min = 8000,
+ .rate_max = 48000,
+ .channels_min = 1,
+ .channels_max = 2,
+ .buffer_bytes_max = 0x3000,
+ .period_bytes_min = 0x40,
+ .period_bytes_max = 0x1800,
+ .periods_min = 2,
+ .periods_max = 3,
+ .fifo_size = 0,
+};
+
+static struct snd_pcm_hardware snd_msnd_capture = {
+ .info = SNDRV_PCM_INFO_MMAP |
+ SNDRV_PCM_INFO_INTERLEAVED |
+ SNDRV_PCM_INFO_MMAP_VALID,
+ .formats = SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S16_LE,
+ .rates = SNDRV_PCM_RATE_8000_48000,
+ .rate_min = 8000,
+ .rate_max = 48000,
+ .channels_min = 1,
+ .channels_max = 2,
+ .buffer_bytes_max = 0x3000,
+ .period_bytes_min = 0x40,
+ .period_bytes_max = 0x1800,
+ .periods_min = 2,
+ .periods_max = 3,
+ .fifo_size = 0,
+};
+
+
+static int snd_msnd_playback_open(struct snd_pcm_substream *substream)
+{
+ struct snd_pcm_runtime *runtime = substream->runtime;
+ struct snd_msnd *chip = snd_pcm_substream_chip(substream);
+
+ set_bit(F_AUDIO_WRITE_INUSE, &chip->flags);
+ clear_bit(F_WRITING, &chip->flags);
+ snd_msnd_enable_irq(chip);
+
+ runtime->dma_area = chip->mappedbase;
+ runtime->dma_bytes = 0x3000;
+
+ chip->playback_substream = substream;
+ runtime->hw = snd_msnd_playback;
+ return 0;
+}
+
+static int snd_msnd_playback_close(struct snd_pcm_substream *substream)
+{
+ struct snd_msnd *chip = snd_pcm_substream_chip(substream);
+
+ snd_msnd_disable_irq(chip);
+ clear_bit(F_AUDIO_WRITE_INUSE, &chip->flags);
+ return 0;
+}
+
+
+static int snd_msnd_playback_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params)
+{
+ int i;
+ struct snd_msnd *chip = snd_pcm_substream_chip(substream);
+ void *pDAQ = chip->mappedbase + DAPQ_DATA_BUFF;
+
+ chip->play_sample_size = snd_pcm_format_width(params_format(params));
+ chip->play_channels = params_channels(params);
+ chip->play_sample_rate = params_rate(params);
+
+ for (i = 0; i < 3; ++i, pDAQ += DAQDS__size) {
+ writew(chip->play_sample_size, pDAQ + DAQDS_wSampleSize);
+ writew(chip->play_channels, pDAQ + DAQDS_wChannels);
+ writew(chip->play_sample_rate, pDAQ + DAQDS_wSampleRate);
+ }
+ /* dont do this here:
+ * snd_msnd_calibrate_adc(chip->play_sample_rate);
+ */
+
+ return 0;
+}
+
+static int snd_msnd_playback_prepare(struct snd_pcm_substream *substream)
+{
+ struct snd_msnd *chip = snd_pcm_substream_chip(substream);
+ unsigned int pcm_size = snd_pcm_lib_buffer_bytes(substream);
+ unsigned int pcm_count = snd_pcm_lib_period_bytes(substream);
+ unsigned int pcm_periods = pcm_size / pcm_count;
+
+ snd_msnd_play_reset_queue(chip, pcm_periods, pcm_count);
+ chip->playDMAPos = 0;
+ return 0;
+}
+
+static int snd_msnd_playback_trigger(struct snd_pcm_substream *substream,
+ int cmd)
+{
+ struct snd_msnd *chip = snd_pcm_substream_chip(substream);
+ int result = 0;
+
+ if (cmd == SNDRV_PCM_TRIGGER_START) {
+ snd_printdd("snd_msnd_playback_trigger(START)\n");
+ chip->banksPlayed = 0;
+ set_bit(F_WRITING, &chip->flags);
+ snd_msnd_DAPQ(chip, 1);
+ } else if (cmd == SNDRV_PCM_TRIGGER_STOP) {
+ snd_printdd("snd_msnd_playback_trigger(STop)\n");
+ /* interrupt diagnostic, comment this out later */
+ clear_bit(F_WRITING, &chip->flags);
+ snd_msnd_send_dsp_cmd(chip, HDEX_PLAY_STOP);
+ } else {
+ snd_printd(KERN_ERR "snd_msnd_playback_trigger(?????)\n");
+ result = -EINVAL;
+ }
+
+ snd_printdd("snd_msnd_playback_trigger() ENDE\n");
+ return result;
+}
+
+static snd_pcm_uframes_t
+snd_msnd_playback_pointer(struct snd_pcm_substream *substream)
+{
+ struct snd_msnd *chip = snd_pcm_substream_chip(substream);
+
+ return bytes_to_frames(substream->runtime, chip->playDMAPos);
+}
+
+
+static struct snd_pcm_ops snd_msnd_playback_ops = {
+ .open = snd_msnd_playback_open,
+ .close = snd_msnd_playback_close,
+ .ioctl = snd_pcm_lib_ioctl,
+ .hw_params = snd_msnd_playback_hw_params,
+ .prepare = snd_msnd_playback_prepare,
+ .trigger = snd_msnd_playback_trigger,
+ .pointer = snd_msnd_playback_pointer,
+};
+
+static int snd_msnd_capture_open(struct snd_pcm_substream *substream)
+{
+ struct snd_pcm_runtime *runtime = substream->runtime;
+ struct snd_msnd *chip = snd_pcm_substream_chip(substream);
+
+ set_bit(F_AUDIO_READ_INUSE, &chip->flags);
+ snd_msnd_enable_irq(chip);
+ runtime->dma_area = chip->mappedbase + 0x3000;
+ runtime->dma_bytes = 0x3000;
+ memset(runtime->dma_area, 0, runtime->dma_bytes);
+ chip->capture_substream = substream;
+ runtime->hw = snd_msnd_capture;
+ return 0;
+}
+
+static int snd_msnd_capture_close(struct snd_pcm_substream *substream)
+{
+ struct snd_msnd *chip = snd_pcm_substream_chip(substream);
+
+ snd_msnd_disable_irq(chip);
+ clear_bit(F_AUDIO_READ_INUSE, &chip->flags);
+ return 0;
+}
+
+static int snd_msnd_capture_prepare(struct snd_pcm_substream *substream)
+{
+ struct snd_msnd *chip = snd_pcm_substream_chip(substream);
+ unsigned int pcm_size = snd_pcm_lib_buffer_bytes(substream);
+ unsigned int pcm_count = snd_pcm_lib_period_bytes(substream);
+ unsigned int pcm_periods = pcm_size / pcm_count;
+
+ snd_msnd_capture_reset_queue(chip, pcm_periods, pcm_count);
+ chip->captureDMAPos = 0;
+ return 0;
+}
+
+static int snd_msnd_capture_trigger(struct snd_pcm_substream *substream,
+ int cmd)
+{
+ struct snd_msnd *chip = snd_pcm_substream_chip(substream);
+
+ if (cmd == SNDRV_PCM_TRIGGER_START) {
+ chip->last_recbank = -1;
+ set_bit(F_READING, &chip->flags);
+ if (snd_msnd_send_dsp_cmd(chip, HDEX_RECORD_START) == 0)
+ return 0;
+
+ clear_bit(F_READING, &chip->flags);
+ } else if (cmd == SNDRV_PCM_TRIGGER_STOP) {
+ clear_bit(F_READING, &chip->flags);
+ snd_msnd_send_dsp_cmd(chip, HDEX_RECORD_STOP);
+ return 0;
+ }
+ return -EINVAL;
+}
+
+
+static snd_pcm_uframes_t
+snd_msnd_capture_pointer(struct snd_pcm_substream *substream)
+{
+ struct snd_pcm_runtime *runtime = substream->runtime;
+ struct snd_msnd *chip = snd_pcm_substream_chip(substream);
+
+ return bytes_to_frames(runtime, chip->captureDMAPos);
+}
+
+
+static int snd_msnd_capture_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params)
+{
+ int i;
+ struct snd_msnd *chip = snd_pcm_substream_chip(substream);
+ void *pDAQ = chip->mappedbase + DARQ_DATA_BUFF;
+
+ chip->capture_sample_size = snd_pcm_format_width(params_format(params));
+ chip->capture_channels = params_channels(params);
+ chip->capture_sample_rate = params_rate(params);
+
+ for (i = 0; i < 3; ++i, pDAQ += DAQDS__size) {
+ writew(chip->capture_sample_size, pDAQ + DAQDS_wSampleSize);
+ writew(chip->capture_channels, pDAQ + DAQDS_wChannels);
+ writew(chip->capture_sample_rate, pDAQ + DAQDS_wSampleRate);
+ }
+ return 0;
+}
+
+
+static struct snd_pcm_ops snd_msnd_capture_ops = {
+ .open = snd_msnd_capture_open,
+ .close = snd_msnd_capture_close,
+ .ioctl = snd_pcm_lib_ioctl,
+ .hw_params = snd_msnd_capture_hw_params,
+ .prepare = snd_msnd_capture_prepare,
+ .trigger = snd_msnd_capture_trigger,
+ .pointer = snd_msnd_capture_pointer,
+};
+
+
+int snd_msnd_pcm(struct snd_card *card, int device,
+ struct snd_pcm **rpcm)
+{
+ struct snd_msnd *chip = card->private_data;
+ struct snd_pcm *pcm;
+ int err;
+
+ err = snd_pcm_new(card, "MSNDPINNACLE", device, 1, 1, &pcm);
+ if (err < 0)
+ return err;
+
+ snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &snd_msnd_playback_ops);
+ snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &snd_msnd_capture_ops);
+
+ pcm->private_data = chip;
+ strcpy(pcm->name, "Hurricane");
+
+
+ if (rpcm)
+ *rpcm = pcm;
+ return 0;
+}
+EXPORT_SYMBOL(snd_msnd_pcm);
+
+MODULE_DESCRIPTION("Common routines for Turtle Beach Multisound drivers");
+MODULE_LICENSE("GPL");
+
diff --git a/sound/isa/msnd/msnd.h b/sound/isa/msnd/msnd.h
new file mode 100644
index 00000000000..3773e242b58
--- /dev/null
+++ b/sound/isa/msnd/msnd.h
@@ -0,0 +1,308 @@
+/*********************************************************************
+ *
+ * msnd.h
+ *
+ * Turtle Beach MultiSound Sound Card Driver for Linux
+ *
+ * Some parts of this header file were derived from the Turtle Beach
+ * MultiSound Driver Development Kit.
+ *
+ * Copyright (C) 1998 Andrew Veliath
+ * Copyright (C) 1993 Turtle Beach Systems, Inc.
+ *
+ * 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ ********************************************************************/
+#ifndef __MSND_H
+#define __MSND_H
+
+#define DEFSAMPLERATE 44100
+#define DEFSAMPLESIZE SNDRV_PCM_FORMAT_S16
+#define DEFCHANNELS 1
+
+#define SRAM_BANK_SIZE 0x8000
+#define SRAM_CNTL_START 0x7F00
+#define SMA_STRUCT_START 0x7F40
+
+#define DSP_BASE_ADDR 0x4000
+#define DSP_BANK_BASE 0x4000
+
+#define AGND 0x01
+#define SIGNAL 0x02
+
+#define EXT_DSP_BIT_DCAL 0x0001
+#define EXT_DSP_BIT_MIDI_CON 0x0002
+
+#define BUFFSIZE 0x8000
+#define HOSTQ_SIZE 0x40
+
+#define DAP_BUFF_SIZE 0x2400
+
+#define DAPQ_STRUCT_SIZE 0x10
+#define DARQ_STRUCT_SIZE 0x10
+#define DAPQ_BUFF_SIZE (3 * 0x10)
+#define DARQ_BUFF_SIZE (3 * 0x10)
+#define MODQ_BUFF_SIZE 0x400
+
+#define DAPQ_DATA_BUFF 0x6C00
+#define DARQ_DATA_BUFF 0x6C30
+#define MODQ_DATA_BUFF 0x6C60
+#define MIDQ_DATA_BUFF 0x7060
+
+#define DAPQ_OFFSET SRAM_CNTL_START
+#define DARQ_OFFSET (SRAM_CNTL_START + 0x08)
+#define MODQ_OFFSET (SRAM_CNTL_START + 0x10)
+#define MIDQ_OFFSET (SRAM_CNTL_START + 0x18)
+#define DSPQ_OFFSET (SRAM_CNTL_START + 0x20)
+
+#define HP_ICR 0x00
+#define HP_CVR 0x01
+#define HP_ISR 0x02
+#define HP_IVR 0x03
+#define HP_NU 0x04
+#define HP_INFO 0x04
+#define HP_TXH 0x05
+#define HP_RXH 0x05
+#define HP_TXM 0x06
+#define HP_RXM 0x06
+#define HP_TXL 0x07
+#define HP_RXL 0x07
+
+#define HP_ICR_DEF 0x00
+#define HP_CVR_DEF 0x12
+#define HP_ISR_DEF 0x06
+#define HP_IVR_DEF 0x0f
+#define HP_NU_DEF 0x00
+
+#define HP_IRQM 0x09
+
+#define HPR_BLRC 0x08
+#define HPR_SPR1 0x09
+#define HPR_SPR2 0x0A
+#define HPR_TCL0 0x0B
+#define HPR_TCL1 0x0C
+#define HPR_TCL2 0x0D
+#define HPR_TCL3 0x0E
+#define HPR_TCL4 0x0F
+
+#define HPICR_INIT 0x80
+#define HPICR_HM1 0x40
+#define HPICR_HM0 0x20
+#define HPICR_HF1 0x10
+#define HPICR_HF0 0x08
+#define HPICR_TREQ 0x02
+#define HPICR_RREQ 0x01
+
+#define HPCVR_HC 0x80
+
+#define HPISR_HREQ 0x80
+#define HPISR_DMA 0x40
+#define HPISR_HF3 0x10
+#define HPISR_HF2 0x08
+#define HPISR_TRDY 0x04
+#define HPISR_TXDE 0x02
+#define HPISR_RXDF 0x01
+
+#define HPIO_290 0
+#define HPIO_260 1
+#define HPIO_250 2
+#define HPIO_240 3
+#define HPIO_230 4
+#define HPIO_220 5
+#define HPIO_210 6
+#define HPIO_3E0 7
+
+#define HPMEM_NONE 0
+#define HPMEM_B000 1
+#define HPMEM_C800 2
+#define HPMEM_D000 3
+#define HPMEM_D400 4
+#define HPMEM_D800 5
+#define HPMEM_E000 6
+#define HPMEM_E800 7
+
+#define HPIRQ_NONE 0
+#define HPIRQ_5 1
+#define HPIRQ_7 2
+#define HPIRQ_9 3
+#define HPIRQ_10 4
+#define HPIRQ_11 5
+#define HPIRQ_12 6
+#define HPIRQ_15 7
+
+#define HIMT_PLAY_DONE 0x00
+#define HIMT_RECORD_DONE 0x01
+#define HIMT_MIDI_EOS 0x02
+#define HIMT_MIDI_OUT 0x03
+
+#define HIMT_MIDI_IN_UCHAR 0x0E
+#define HIMT_DSP 0x0F
+
+#define HDEX_BASE 0x92
+#define HDEX_PLAY_START (0 + HDEX_BASE)
+#define HDEX_PLAY_STOP (1 + HDEX_BASE)
+#define HDEX_PLAY_PAUSE (2 + HDEX_BASE)
+#define HDEX_PLAY_RESUME (3 + HDEX_BASE)
+#define HDEX_RECORD_START (4 + HDEX_BASE)
+#define HDEX_RECORD_STOP (5 + HDEX_BASE)
+#define HDEX_MIDI_IN_START (6 + HDEX_BASE)
+#define HDEX_MIDI_IN_STOP (7 + HDEX_BASE)
+#define HDEX_MIDI_OUT_START (8 + HDEX_BASE)
+#define HDEX_MIDI_OUT_STOP (9 + HDEX_BASE)
+#define HDEX_AUX_REQ (10 + HDEX_BASE)
+
+#define HDEXAR_CLEAR_PEAKS 1
+#define HDEXAR_IN_SET_POTS 2
+#define HDEXAR_AUX_SET_POTS 3
+#define HDEXAR_CAL_A_TO_D 4
+#define HDEXAR_RD_EXT_DSP_BITS 5
+
+/* Pinnacle only HDEXAR defs */
+#define HDEXAR_SET_ANA_IN 0
+#define HDEXAR_SET_SYNTH_IN 4
+#define HDEXAR_READ_DAT_IN 5
+#define HDEXAR_MIC_SET_POTS 6
+#define HDEXAR_SET_DAT_IN 7
+
+#define HDEXAR_SET_SYNTH_48 8
+#define HDEXAR_SET_SYNTH_44 9
+
+#define HIWORD(l) ((u16)((((u32)(l)) >> 16) & 0xFFFF))
+#define LOWORD(l) ((u16)(u32)(l))
+#define HIBYTE(w) ((u8)(((u16)(w) >> 8) & 0xFF))
+#define LOBYTE(w) ((u8)(w))
+#define MAKELONG(low, hi) ((long)(((u16)(low))|(((u32)((u16)(hi)))<<16)))
+#define MAKEWORD(low, hi) ((u16)(((u8)(low))|(((u16)((u8)(hi)))<<8)))
+
+#define PCTODSP_OFFSET(w) (u16)((w)/2)
+#define PCTODSP_BASED(w) (u16)(((w)/2) + DSP_BASE_ADDR)
+#define DSPTOPC_BASED(w) (((w) - DSP_BASE_ADDR) * 2)
+
+#ifdef SLOWIO
+# undef outb
+# undef inb
+# define outb outb_p
+# define inb inb_p
+#endif
+
+/* JobQueueStruct */
+#define JQS_wStart 0x00
+#define JQS_wSize 0x02
+#define JQS_wHead 0x04
+#define JQS_wTail 0x06
+#define JQS__size 0x08
+
+/* DAQueueDataStruct */
+#define DAQDS_wStart 0x00
+#define DAQDS_wSize 0x02
+#define DAQDS_wFormat 0x04
+#define DAQDS_wSampleSize 0x06
+#define DAQDS_wChannels 0x08
+#define DAQDS_wSampleRate 0x0A
+#define DAQDS_wIntMsg 0x0C
+#define DAQDS_wFlags 0x0E
+#define DAQDS__size 0x10
+
+#include <sound/pcm.h>
+
+struct snd_msnd {
+ void __iomem *mappedbase;
+ int play_period_bytes;
+ int playLimit;
+ int playPeriods;
+ int playDMAPos;
+ int banksPlayed;
+ int captureDMAPos;
+ int capturePeriodBytes;
+ int captureLimit;
+ int capturePeriods;
+ struct snd_card *card;
+ void *msndmidi_mpu;
+ struct snd_rawmidi *rmidi;
+
+ /* Hardware resources */
+ long io;
+ int memid, irqid;
+ int irq, irq_ref;
+ unsigned long base;
+
+ /* Motorola 56k DSP SMA */
+ void __iomem *SMA;
+ void __iomem *DAPQ;
+ void __iomem *DARQ;
+ void __iomem *MODQ;
+ void __iomem *MIDQ;
+ void __iomem *DSPQ;
+ int dspq_data_buff, dspq_buff_size;
+
+ /* State variables */
+ enum { msndClassic, msndPinnacle } type;
+ mode_t mode;
+ unsigned long flags;
+#define F_RESETTING 0
+#define F_HAVEDIGITAL 1
+#define F_AUDIO_WRITE_INUSE 2
+#define F_WRITING 3
+#define F_WRITEBLOCK 4
+#define F_WRITEFLUSH 5
+#define F_AUDIO_READ_INUSE 6
+#define F_READING 7
+#define F_READBLOCK 8
+#define F_EXT_MIDI_INUSE 9
+#define F_HDR_MIDI_INUSE 10
+#define F_DISABLE_WRITE_NDELAY 11
+ spinlock_t lock;
+ spinlock_t mixer_lock;
+ int nresets;
+ unsigned recsrc;
+#define LEVEL_ENTRIES 32
+ int left_levels[LEVEL_ENTRIES];
+ int right_levels[LEVEL_ENTRIES];
+ int calibrate_signal;
+ int play_sample_size, play_sample_rate, play_channels;
+ int play_ndelay;
+ int capture_sample_size, capture_sample_rate, capture_channels;
+ int capture_ndelay;
+ u8 bCurrentMidiPatch;
+
+ int last_playbank, last_recbank;
+ struct snd_pcm_substream *playback_substream;
+ struct snd_pcm_substream *capture_substream;
+
+};
+
+void snd_msnd_init_queue(void *base, int start, int size);
+
+int snd_msnd_send_dsp_cmd(struct snd_msnd *chip, u8 cmd);
+int snd_msnd_send_word(struct snd_msnd *chip,
+ unsigned char high,
+ unsigned char mid,
+ unsigned char low);
+int snd_msnd_upload_host(struct snd_msnd *chip,
+ const u8 *bin, int len);
+int snd_msnd_enable_irq(struct snd_msnd *chip);
+int snd_msnd_disable_irq(struct snd_msnd *chip);
+void snd_msnd_dsp_halt(struct snd_msnd *chip, struct file *file);
+int snd_msnd_DAPQ(struct snd_msnd *chip, int start);
+int snd_msnd_DARQ(struct snd_msnd *chip, int start);
+int snd_msnd_pcm(struct snd_card *card, int device, struct snd_pcm **rpcm);
+
+int snd_msndmidi_new(struct snd_card *card, int device);
+void snd_msndmidi_input_read(void *mpu);
+
+void snd_msndmix_setup(struct snd_msnd *chip);
+int __devinit snd_msndmix_new(struct snd_card *card);
+int snd_msndmix_force_recsrc(struct snd_msnd *chip, int recsrc);
+#endif /* __MSND_H */
diff --git a/sound/isa/msnd/msnd_classic.c b/sound/isa/msnd/msnd_classic.c
new file mode 100644
index 00000000000..3b23a096fa4
--- /dev/null
+++ b/sound/isa/msnd/msnd_classic.c
@@ -0,0 +1,3 @@
+/* The work is in msnd_pinnacle.c, just define MSND_CLASSIC before it. */
+#define MSND_CLASSIC
+#include "msnd_pinnacle.c"
diff --git a/sound/isa/msnd/msnd_classic.h b/sound/isa/msnd/msnd_classic.h
new file mode 100644
index 00000000000..f18d5fa5baf
--- /dev/null
+++ b/sound/isa/msnd/msnd_classic.h
@@ -0,0 +1,129 @@
+/*********************************************************************
+ *
+ * msnd_classic.h
+ *
+ * Turtle Beach MultiSound Sound Card Driver for Linux
+ *
+ * Some parts of this header file were derived from the Turtle Beach
+ * MultiSound Driver Development Kit.
+ *
+ * Copyright (C) 1998 Andrew Veliath
+ * Copyright (C) 1993 Turtle Beach Systems, Inc.
+ *
+ * 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ ********************************************************************/
+#ifndef __MSND_CLASSIC_H
+#define __MSND_CLASSIC_H
+
+#define DSP_NUMIO 0x10
+
+#define HP_MEMM 0x08
+
+#define HP_BITM 0x0E
+#define HP_WAIT 0x0D
+#define HP_DSPR 0x0A
+#define HP_PROR 0x0B
+#define HP_BLKS 0x0C
+
+#define HPPRORESET_OFF 0
+#define HPPRORESET_ON 1
+
+#define HPDSPRESET_OFF 0
+#define HPDSPRESET_ON 1
+
+#define HPBLKSEL_0 0
+#define HPBLKSEL_1 1
+
+#define HPWAITSTATE_0 0
+#define HPWAITSTATE_1 1
+
+#define HPBITMODE_16 0
+#define HPBITMODE_8 1
+
+#define HIDSP_INT_PLAY_UNDER 0x00
+#define HIDSP_INT_RECORD_OVER 0x01
+#define HIDSP_INPUT_CLIPPING 0x02
+#define HIDSP_MIDI_IN_OVER 0x10
+#define HIDSP_MIDI_OVERRUN_ERR 0x13
+
+#define TIME_PRO_RESET_DONE 0x028A
+#define TIME_PRO_SYSEX 0x0040
+#define TIME_PRO_RESET 0x0032
+
+#define DAR_BUFF_SIZE 0x2000
+
+#define MIDQ_BUFF_SIZE 0x200
+#define DSPQ_BUFF_SIZE 0x40
+
+#define DSPQ_DATA_BUFF 0x7260
+
+#define MOP_SYNTH 0x10
+#define MOP_EXTOUT 0x32
+#define MOP_EXTTHRU 0x02
+#define MOP_OUTMASK 0x01
+
+#define MIP_EXTIN 0x01
+#define MIP_SYNTH 0x00
+#define MIP_INMASK 0x32
+
+/* Classic SMA Common Data */
+#define SMA_wCurrPlayBytes 0x0000
+#define SMA_wCurrRecordBytes 0x0002
+#define SMA_wCurrPlayVolLeft 0x0004
+#define SMA_wCurrPlayVolRight 0x0006
+#define SMA_wCurrInVolLeft 0x0008
+#define SMA_wCurrInVolRight 0x000a
+#define SMA_wUser_3 0x000c
+#define SMA_wUser_4 0x000e
+#define SMA_dwUser_5 0x0010
+#define SMA_dwUser_6 0x0014
+#define SMA_wUser_7 0x0018
+#define SMA_wReserved_A 0x001a
+#define SMA_wReserved_B 0x001c
+#define SMA_wReserved_C 0x001e
+#define SMA_wReserved_D 0x0020
+#define SMA_wReserved_E 0x0022
+#define SMA_wReserved_F 0x0024
+#define SMA_wReserved_G 0x0026
+#define SMA_wReserved_H 0x0028
+#define SMA_wCurrDSPStatusFlags 0x002a
+#define SMA_wCurrHostStatusFlags 0x002c
+#define SMA_wCurrInputTagBits 0x002e
+#define SMA_wCurrLeftPeak 0x0030
+#define SMA_wCurrRightPeak 0x0032
+#define SMA_wExtDSPbits 0x0034
+#define SMA_bExtHostbits 0x0036
+#define SMA_bBoardLevel 0x0037
+#define SMA_bInPotPosRight 0x0038
+#define SMA_bInPotPosLeft 0x0039
+#define SMA_bAuxPotPosRight 0x003a
+#define SMA_bAuxPotPosLeft 0x003b
+#define SMA_wCurrMastVolLeft 0x003c
+#define SMA_wCurrMastVolRight 0x003e
+#define SMA_bUser_12 0x0040
+#define SMA_bUser_13 0x0041
+#define SMA_wUser_14 0x0042
+#define SMA_wUser_15 0x0044
+#define SMA_wCalFreqAtoD 0x0046
+#define SMA_wUser_16 0x0048
+#define SMA_wUser_17 0x004a
+#define SMA__size 0x004c
+
+#define INITCODEFILE "turtlebeach/msndinit.bin"
+#define PERMCODEFILE "turtlebeach/msndperm.bin"
+#define LONGNAME "MultiSound (Classic/Monterey/Tahiti)"
+
+#endif /* __MSND_CLASSIC_H */
diff --git a/sound/isa/msnd/msnd_midi.c b/sound/isa/msnd/msnd_midi.c
new file mode 100644
index 00000000000..cb9aa4c4edd
--- /dev/null
+++ b/sound/isa/msnd/msnd_midi.c
@@ -0,0 +1,180 @@
+/*
+ * Copyright (c) by Jaroslav Kysela <perex@perex.cz>
+ * Copyright (c) 2009 by Krzysztof Helt
+ * Routines for control of MPU-401 in UART mode
+ *
+ * MPU-401 supports UART mode which is not capable generate transmit
+ * interrupts thus output is done via polling. Also, if irq < 0, then
+ * input is done also via polling. Do not expect good performance.
+ *
+ *
+ * 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
+ *
+ */
+
+#include <linux/io.h>
+#include <linux/delay.h>
+#include <linux/ioport.h>
+#include <linux/errno.h>
+#include <sound/core.h>
+#include <sound/rawmidi.h>
+
+#include "msnd.h"
+
+#define MSNDMIDI_MODE_BIT_INPUT 0
+#define MSNDMIDI_MODE_BIT_OUTPUT 1
+#define MSNDMIDI_MODE_BIT_INPUT_TRIGGER 2
+#define MSNDMIDI_MODE_BIT_OUTPUT_TRIGGER 3
+
+struct snd_msndmidi {
+ struct snd_msnd *dev;
+
+ unsigned long mode; /* MSNDMIDI_MODE_XXXX */
+
+ struct snd_rawmidi_substream *substream_input;
+
+ spinlock_t input_lock;
+};
+
+/*
+ * input/output open/close - protected by open_mutex in rawmidi.c
+ */
+static int snd_msndmidi_input_open(struct snd_rawmidi_substream *substream)
+{
+ struct snd_msndmidi *mpu;
+
+ snd_printdd("snd_msndmidi_input_open()\n");
+
+ mpu = substream->rmidi->private_data;
+
+ mpu->substream_input = substream;
+
+ snd_msnd_enable_irq(mpu->dev);
+
+ snd_msnd_send_dsp_cmd(mpu->dev, HDEX_MIDI_IN_START);
+ set_bit(MSNDMIDI_MODE_BIT_INPUT, &mpu->mode);
+ return 0;
+}
+
+static int snd_msndmidi_input_close(struct snd_rawmidi_substream *substream)
+{
+ struct snd_msndmidi *mpu;
+
+ mpu = substream->rmidi->private_data;
+ snd_msnd_send_dsp_cmd(mpu->dev, HDEX_MIDI_IN_STOP);
+ clear_bit(MSNDMIDI_MODE_BIT_INPUT, &mpu->mode);
+ mpu->substream_input = NULL;
+ snd_msnd_disable_irq(mpu->dev);
+ return 0;
+}
+
+static void snd_msndmidi_input_drop(struct snd_msndmidi *mpu)
+{
+ u16 tail;
+
+ tail = readw(mpu->dev->MIDQ + JQS_wTail);
+ writew(tail, mpu->dev->MIDQ + JQS_wHead);
+}
+
+/*
+ * trigger input
+ */
+static void snd_msndmidi_input_trigger(struct snd_rawmidi_substream *substream,
+ int up)
+{
+ unsigned long flags;
+ struct snd_msndmidi *mpu;
+
+ snd_printdd("snd_msndmidi_input_trigger(, %i)\n", up);
+
+ mpu = substream->rmidi->private_data;
+ spin_lock_irqsave(&mpu->input_lock, flags);
+ if (up) {
+ if (!test_and_set_bit(MSNDMIDI_MODE_BIT_INPUT_TRIGGER,
+ &mpu->mode))
+ snd_msndmidi_input_drop(mpu);
+ } else {
+ clear_bit(MSNDMIDI_MODE_BIT_INPUT_TRIGGER, &mpu->mode);
+ }
+ spin_unlock_irqrestore(&mpu->input_lock, flags);
+ if (up)
+ snd_msndmidi_input_read(mpu);
+}
+
+void snd_msndmidi_input_read(void *mpuv)
+{
+ unsigned long flags;
+ struct snd_msndmidi *mpu = mpuv;
+ void *pwMIDQData = mpu->dev->mappedbase + MIDQ_DATA_BUFF;
+
+ spin_lock_irqsave(&mpu->input_lock, flags);
+ while (readw(mpu->dev->MIDQ + JQS_wTail) !=
+ readw(mpu->dev->MIDQ + JQS_wHead)) {
+ u16 wTmp, val;
+ val = readw(pwMIDQData + 2 * readw(mpu->dev->MIDQ + JQS_wHead));
+
+ if (test_bit(MSNDMIDI_MODE_BIT_INPUT_TRIGGER,
+ &mpu->mode))
+ snd_rawmidi_receive(mpu->substream_input,
+ (unsigned char *)&val, 1);
+
+ wTmp = readw(mpu->dev->MIDQ + JQS_wHead) + 1;
+ if (wTmp > readw(mpu->dev->MIDQ + JQS_wSize))
+ writew(0, mpu->dev->MIDQ + JQS_wHead);
+ else
+ writew(wTmp, mpu->dev->MIDQ + JQS_wHead);
+ }
+ spin_unlock_irqrestore(&mpu->input_lock, flags);
+}
+EXPORT_SYMBOL(snd_msndmidi_input_read);
+
+static struct snd_rawmidi_ops snd_msndmidi_input = {
+ .open = snd_msndmidi_input_open,
+ .close = snd_msndmidi_input_close,
+ .trigger = snd_msndmidi_input_trigger,
+};
+
+static void snd_msndmidi_free(struct snd_rawmidi *rmidi)
+{
+ struct snd_msndmidi *mpu = rmidi->private_data;
+ kfree(mpu);
+}
+
+int snd_msndmidi_new(struct snd_card *card, int device)
+{
+ struct snd_msnd *chip = card->private_data;
+ struct snd_msndmidi *mpu;
+ struct snd_rawmidi *rmidi;
+ int err;
+
+ err = snd_rawmidi_new(card, "MSND-MIDI", device, 1, 1, &rmidi);
+ if (err < 0)
+ return err;
+ mpu = kcalloc(1, sizeof(*mpu), GFP_KERNEL);
+ if (mpu == NULL) {
+ snd_device_free(card, rmidi);
+ return -ENOMEM;
+ }
+ mpu->dev = chip;
+ chip->msndmidi_mpu = mpu;
+ rmidi->private_data = mpu;
+ rmidi->private_free = snd_msndmidi_free;
+ spin_lock_init(&mpu->input_lock);
+ strcpy(rmidi->name, "MSND MIDI");
+ snd_rawmidi_set_ops(rmidi, SNDRV_RAWMIDI_STREAM_INPUT,
+ &snd_msndmidi_input);
+ rmidi->info_flags |= SNDRV_RAWMIDI_INFO_INPUT;
+ return 0;
+}
diff --git a/sound/isa/msnd/msnd_pinnacle.c b/sound/isa/msnd/msnd_pinnacle.c
new file mode 100644
index 00000000000..60b6abd7161
--- /dev/null
+++ b/sound/isa/msnd/msnd_pinnacle.c
@@ -0,0 +1,1238 @@
+/*********************************************************************
+ *
+ * Linux multisound pinnacle/fiji driver for ALSA.
+ *
+ * 2002/06/30 Karsten Wiese:
+ * for now this is only used to build a pinnacle / fiji driver.
+ * the OSS parent of this code is designed to also support
+ * the multisound classic via the file msnd_classic.c.
+ * to make it easier for some brave heart to implemt classic
+ * support in alsa, i left all the MSND_CLASSIC tokens in this file.
+ * but for now this untested & undone.
+ *
+ *
+ * ripped from linux kernel 2.4.18 by Karsten Wiese.
+ *
+ * the following is a copy of the 2.4.18 OSS FREE file-heading comment:
+ *
+ * Turtle Beach MultiSound Sound Card Driver for Linux
+ * msnd_pinnacle.c / msnd_classic.c
+ *
+ * -- If MSND_CLASSIC is defined:
+ *
+ * -> driver for Turtle Beach Classic/Monterey/Tahiti
+ *
+ * -- Else
+ *
+ * -> driver for Turtle Beach Pinnacle/Fiji
+ *
+ * 12-3-2000 Modified IO port validation Steve Sycamore
+ *
+ * Copyright (C) 1998 Andrew Veliath
+ *
+ * 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ ********************************************************************/
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/interrupt.h>
+#include <linux/types.h>
+#include <linux/delay.h>
+#include <linux/ioport.h>
+#include <linux/firmware.h>
+#include <linux/isa.h>
+#include <linux/isapnp.h>
+#include <linux/irq.h>
+#include <linux/io.h>
+
+#include <sound/core.h>
+#include <sound/initval.h>
+#include <sound/asound.h>
+#include <sound/pcm.h>
+#include <sound/mpu401.h>
+
+#ifdef MSND_CLASSIC
+# ifndef __alpha__
+# define SLOWIO
+# endif
+#endif
+#include "msnd.h"
+#ifdef MSND_CLASSIC
+# include "msnd_classic.h"
+# define LOGNAME "msnd_classic"
+#else
+# include "msnd_pinnacle.h"
+# define LOGNAME "snd_msnd_pinnacle"
+#endif
+
+static void __devinit set_default_audio_parameters(struct snd_msnd *chip)
+{
+ chip->play_sample_size = DEFSAMPLESIZE;
+ chip->play_sample_rate = DEFSAMPLERATE;
+ chip->play_channels = DEFCHANNELS;
+ chip->capture_sample_size = DEFSAMPLESIZE;
+ chip->capture_sample_rate = DEFSAMPLERATE;
+ chip->capture_channels = DEFCHANNELS;
+}
+
+static void snd_msnd_eval_dsp_msg(struct snd_msnd *chip, u16 wMessage)
+{
+ switch (HIBYTE(wMessage)) {
+ case HIMT_PLAY_DONE: {
+ if (chip->banksPlayed < 3)
+ snd_printdd("%08X: HIMT_PLAY_DONE: %i\n",
+ (unsigned)jiffies, LOBYTE(wMessage));
+
+ if (chip->last_playbank == LOBYTE(wMessage)) {
+ snd_printdd("chip.last_playbank == LOBYTE(wMessage)\n");
+ break;
+ }
+ chip->banksPlayed++;
+
+ if (test_bit(F_WRITING, &chip->flags))
+ snd_msnd_DAPQ(chip, 0);
+
+ chip->last_playbank = LOBYTE(wMessage);
+ chip->playDMAPos += chip->play_period_bytes;
+ if (chip->playDMAPos > chip->playLimit)
+ chip->playDMAPos = 0;
+ snd_pcm_period_elapsed(chip->playback_substream);
+
+ break;
+ }
+ case HIMT_RECORD_DONE:
+ if (chip->last_recbank == LOBYTE(wMessage))
+ break;
+ chip->last_recbank = LOBYTE(wMessage);
+ chip->captureDMAPos += chip->capturePeriodBytes;
+ if (chip->captureDMAPos > (chip->captureLimit))
+ chip->captureDMAPos = 0;
+
+ if (test_bit(F_READING, &chip->flags))
+ snd_msnd_DARQ(chip, chip->last_recbank);
+
+ snd_pcm_period_elapsed(chip->capture_substream);
+ break;
+
+ case HIMT_DSP:
+ switch (LOBYTE(wMessage)) {
+#ifndef MSND_CLASSIC
+ case HIDSP_PLAY_UNDER:
+#endif
+ case HIDSP_INT_PLAY_UNDER:
+ snd_printd(KERN_WARNING LOGNAME ": Play underflow %i\n",
+ chip->banksPlayed);
+ if (chip->banksPlayed > 2)
+ clear_bit(F_WRITING, &chip->flags);
+ break;
+
+ case HIDSP_INT_RECORD_OVER:
+ snd_printd(KERN_WARNING LOGNAME ": Record overflow\n");
+ clear_bit(F_READING, &chip->flags);
+ break;
+
+ default:
+ snd_printd(KERN_WARNING LOGNAME
+ ": DSP message %d 0x%02x\n",
+ LOBYTE(wMessage), LOBYTE(wMessage));
+ break;
+ }
+ break;
+
+ case HIMT_MIDI_IN_UCHAR:
+ if (chip->msndmidi_mpu)
+ snd_msndmidi_input_read(chip->msndmidi_mpu);
+ break;
+
+ default:
+ snd_printd(KERN_WARNING LOGNAME ": HIMT message %d 0x%02x\n",
+ HIBYTE(wMessage), HIBYTE(wMessage));
+ break;
+ }
+}
+
+static irqreturn_t snd_msnd_interrupt(int irq, void *dev_id)
+{
+ struct snd_msnd *chip = dev_id;
+ void *pwDSPQData = chip->mappedbase + DSPQ_DATA_BUFF;
+
+ /* Send ack to DSP */
+ /* inb(chip->io + HP_RXL); */
+
+ /* Evaluate queued DSP messages */
+ while (readw(chip->DSPQ + JQS_wTail) != readw(chip->DSPQ + JQS_wHead)) {
+ u16 wTmp;
+
+ snd_msnd_eval_dsp_msg(chip,
+ readw(pwDSPQData + 2 * readw(chip->DSPQ + JQS_wHead)));
+
+ wTmp = readw(chip->DSPQ + JQS_wHead) + 1;
+ if (wTmp > readw(chip->DSPQ + JQS_wSize))
+ writew(0, chip->DSPQ + JQS_wHead);
+ else
+ writew(wTmp, chip->DSPQ + JQS_wHead);
+ }
+ /* Send ack to DSP */
+ inb(chip->io + HP_RXL);
+ return IRQ_HANDLED;
+}
+
+
+static int snd_msnd_reset_dsp(long io, unsigned char *info)
+{
+ int timeout = 100;
+
+ outb(HPDSPRESET_ON, io + HP_DSPR);
+ msleep(1);
+#ifndef MSND_CLASSIC
+ if (info)
+ *info = inb(io + HP_INFO);
+#endif
+ outb(HPDSPRESET_OFF, io + HP_DSPR);
+ msleep(1);
+ while (timeout-- > 0) {
+ if (inb(io + HP_CVR) == HP_CVR_DEF)
+ return 0;
+ msleep(1);
+ }
+ snd_printk(KERN_ERR LOGNAME ": Cannot reset DSP\n");
+
+ return -EIO;
+}
+
+static int __devinit snd_msnd_probe(struct snd_card *card)
+{
+ struct snd_msnd *chip = card->private_data;
+ unsigned char info;
+#ifndef MSND_CLASSIC
+ char *xv, *rev = NULL;
+ char *pin = "TB Pinnacle", *fiji = "TB Fiji";
+ char *pinfiji = "TB Pinnacle/Fiji";
+#endif
+
+ if (!request_region(chip->io, DSP_NUMIO, "probing")) {
+ snd_printk(KERN_ERR LOGNAME ": I/O port conflict\n");
+ return -ENODEV;
+ }
+
+ if (snd_msnd_reset_dsp(chip->io, &info) < 0) {
+ release_region(chip->io, DSP_NUMIO);
+ return -ENODEV;
+ }
+
+#ifdef MSND_CLASSIC
+ strcpy(card->shortname, "Classic/Tahiti/Monterey");
+ strcpy(card->longname, "Turtle Beach Multisound");
+ printk(KERN_INFO LOGNAME ": %s, "
+ "I/O 0x%lx-0x%lx, IRQ %d, memory mapped to 0x%lX-0x%lX\n",
+ card->shortname,
+ chip->io, chip->io + DSP_NUMIO - 1,
+ chip->irq,
+ chip->base, chip->base + 0x7fff);
+#else
+ switch (info >> 4) {
+ case 0xf:
+ xv = "<= 1.15";
+ break;
+ case 0x1:
+ xv = "1.18/1.2";
+ break;
+ case 0x2:
+ xv = "1.3";
+ break;
+ case 0x3:
+ xv = "1.4";
+ break;
+ default:
+ xv = "unknown";
+ break;
+ }
+
+ switch (info & 0x7) {
+ case 0x0:
+ rev = "I";
+ strcpy(card->shortname, pin);
+ break;
+ case 0x1:
+ rev = "F";
+ strcpy(card->shortname, pin);
+ break;
+ case 0x2:
+ rev = "G";
+ strcpy(card->shortname, pin);
+ break;
+ case 0x3:
+ rev = "H";
+ strcpy(card->shortname, pin);
+ break;
+ case 0x4:
+ rev = "E";
+ strcpy(card->shortname, fiji);
+ break;
+ case 0x5:
+ rev = "C";
+ strcpy(card->shortname, fiji);
+ break;
+ case 0x6:
+ rev = "D";
+ strcpy(card->shortname, fiji);
+ break;
+ case 0x7:
+ rev = "A-B (Fiji) or A-E (Pinnacle)";
+ strcpy(card->shortname, pinfiji);
+ break;
+ }
+ strcpy(card->longname, "Turtle Beach Multisound Pinnacle");
+ printk(KERN_INFO LOGNAME ": %s revision %s, Xilinx version %s, "
+ "I/O 0x%lx-0x%lx, IRQ %d, memory mapped to 0x%lX-0x%lX\n",
+ card->shortname,
+ rev, xv,
+ chip->io, chip->io + DSP_NUMIO - 1,
+ chip->irq,
+ chip->base, chip->base + 0x7fff);
+#endif
+
+ release_region(chip->io, DSP_NUMIO);
+ return 0;
+}
+
+static int snd_msnd_init_sma(struct snd_msnd *chip)
+{
+ static int initted;
+ u16 mastVolLeft, mastVolRight;
+ unsigned long flags;
+
+#ifdef MSND_CLASSIC
+ outb(chip->memid, chip->io + HP_MEMM);
+#endif
+ outb(HPBLKSEL_0, chip->io + HP_BLKS);
+ /* Motorola 56k shared memory base */
+ chip->SMA = chip->mappedbase + SMA_STRUCT_START;
+
+ if (initted) {
+ mastVolLeft = readw(chip->SMA + SMA_wCurrMastVolLeft);
+ mastVolRight = readw(chip->SMA + SMA_wCurrMastVolRight);
+ } else
+ mastVolLeft = mastVolRight = 0;
+ memset_io(chip->mappedbase, 0, 0x8000);
+
+ /* Critical section: bank 1 access */
+ spin_lock_irqsave(&chip->lock, flags);
+ outb(HPBLKSEL_1, chip->io + HP_BLKS);
+ memset_io(chip->mappedbase, 0, 0x8000);
+ outb(HPBLKSEL_0, chip->io + HP_BLKS);
+ spin_unlock_irqrestore(&chip->lock, flags);
+
+ /* Digital audio play queue */
+ chip->DAPQ = chip->mappedbase + DAPQ_OFFSET;
+ snd_msnd_init_queue(chip->DAPQ, DAPQ_DATA_BUFF, DAPQ_BUFF_SIZE);
+
+ /* Digital audio record queue */
+ chip->DARQ = chip->mappedbase + DARQ_OFFSET;
+ snd_msnd_init_queue(chip->DARQ, DARQ_DATA_BUFF, DARQ_BUFF_SIZE);
+
+ /* MIDI out queue */
+ chip->MODQ = chip->mappedbase + MODQ_OFFSET;
+ snd_msnd_init_queue(chip->MODQ, MODQ_DATA_BUFF, MODQ_BUFF_SIZE);
+
+ /* MIDI in queue */
+ chip->MIDQ = chip->mappedbase + MIDQ_OFFSET;
+ snd_msnd_init_queue(chip->MIDQ, MIDQ_DATA_BUFF, MIDQ_BUFF_SIZE);
+
+ /* DSP -> host message queue */
+ chip->DSPQ = chip->mappedbase + DSPQ_OFFSET;
+ snd_msnd_init_queue(chip->DSPQ, DSPQ_DATA_BUFF, DSPQ_BUFF_SIZE);
+
+ /* Setup some DSP values */
+#ifndef MSND_CLASSIC
+ writew(1, chip->SMA + SMA_wCurrPlayFormat);
+ writew(chip->play_sample_size, chip->SMA + SMA_wCurrPlaySampleSize);
+ writew(chip->play_channels, chip->SMA + SMA_wCurrPlayChannels);
+ writew(chip->play_sample_rate, chip->SMA + SMA_wCurrPlaySampleRate);
+#endif
+ writew(chip->play_sample_rate, chip->SMA + SMA_wCalFreqAtoD);
+ writew(mastVolLeft, chip->SMA + SMA_wCurrMastVolLeft);
+ writew(mastVolRight, chip->SMA + SMA_wCurrMastVolRight);
+#ifndef MSND_CLASSIC
+ writel(0x00010000, chip->SMA + SMA_dwCurrPlayPitch);
+ writel(0x00000001, chip->SMA + SMA_dwCurrPlayRate);
+#endif
+ writew(0x303, chip->SMA + SMA_wCurrInputTagBits);
+
+ initted = 1;
+
+ return 0;
+}
+
+
+static int upload_dsp_code(struct snd_card *card)
+{
+ struct snd_msnd *chip = card->private_data;
+ const struct firmware *init_fw = NULL, *perm_fw = NULL;
+ int err;
+
+ outb(HPBLKSEL_0, chip->io + HP_BLKS);
+
+ err = request_firmware(&init_fw, INITCODEFILE, card->dev);
+ if (err < 0) {
+ printk(KERN_ERR LOGNAME ": Error loading " INITCODEFILE);
+ goto cleanup1;
+ }
+ err = request_firmware(&perm_fw, PERMCODEFILE, card->dev);
+ if (err < 0) {
+ printk(KERN_ERR LOGNAME ": Error loading " PERMCODEFILE);
+ goto cleanup;
+ }
+
+ memcpy_toio(chip->mappedbase, perm_fw->data, perm_fw->size);
+ if (snd_msnd_upload_host(chip, init_fw->data, init_fw->size) < 0) {
+ printk(KERN_WARNING LOGNAME ": Error uploading to DSP\n");
+ err = -ENODEV;
+ goto cleanup;
+ }
+ printk(KERN_INFO LOGNAME ": DSP firmware uploaded\n");
+ err = 0;
+
+cleanup:
+ release_firmware(perm_fw);
+cleanup1:
+ release_firmware(init_fw);
+ return err;
+}
+
+#ifdef MSND_CLASSIC
+static void reset_proteus(struct snd_msnd *chip)
+{
+ outb(HPPRORESET_ON, chip->io + HP_PROR);
+ msleep(TIME_PRO_RESET);
+ outb(HPPRORESET_OFF, chip->io + HP_PROR);
+ msleep(TIME_PRO_RESET_DONE);
+}
+#endif
+
+static int snd_msnd_initialize(struct snd_card *card)
+{
+ struct snd_msnd *chip = card->private_data;
+ int err, timeout;
+
+#ifdef MSND_CLASSIC
+ outb(HPWAITSTATE_0, chip->io + HP_WAIT);
+ outb(HPBITMODE_16, chip->io + HP_BITM);
+
+ reset_proteus(chip);
+#endif
+ err = snd_msnd_init_sma(chip);
+ if (err < 0) {
+ printk(KERN_WARNING LOGNAME ": Cannot initialize SMA\n");
+ return err;
+ }
+
+ err = snd_msnd_reset_dsp(chip->io, NULL);
+ if (err < 0)
+ return err;
+
+ err = upload_dsp_code(card);
+ if (err < 0) {
+ printk(KERN_WARNING LOGNAME ": Cannot upload DSP code\n");
+ return err;
+ }
+
+ timeout = 200;
+
+ while (readw(chip->mappedbase)) {
+ msleep(1);
+ if (!timeout--) {
+ snd_printd(KERN_ERR LOGNAME ": DSP reset timeout\n");
+ return -EIO;
+ }
+ }
+
+ snd_msndmix_setup(chip);
+ return 0;
+}
+
+static int snd_msnd_dsp_full_reset(struct snd_card *card)
+{
+ struct snd_msnd *chip = card->private_data;
+ int rv;
+
+ if (test_bit(F_RESETTING, &chip->flags) || ++chip->nresets > 10)
+ return 0;
+
+ set_bit(F_RESETTING, &chip->flags);
+ snd_msnd_dsp_halt(chip, NULL); /* Unconditionally halt */
+
+ rv = snd_msnd_initialize(card);
+ if (rv)
+ printk(KERN_WARNING LOGNAME ": DSP reset failed\n");
+ snd_msndmix_force_recsrc(chip, 0);
+ clear_bit(F_RESETTING, &chip->flags);
+ return rv;
+}
+
+static int snd_msnd_dev_free(struct snd_device *device)
+{
+ snd_printdd("snd_msnd_chip_free()\n");
+ return 0;
+}
+
+static int snd_msnd_send_dsp_cmd_chk(struct snd_msnd *chip, u8 cmd)
+{
+ if (snd_msnd_send_dsp_cmd(chip, cmd) == 0)
+ return 0;
+ snd_msnd_dsp_full_reset(chip->card);
+ return snd_msnd_send_dsp_cmd(chip, cmd);
+}
+
+static int __devinit snd_msnd_calibrate_adc(struct snd_msnd *chip, u16 srate)
+{
+ snd_printdd("snd_msnd_calibrate_adc(%i)\n", srate);
+ writew(srate, chip->SMA + SMA_wCalFreqAtoD);
+ if (chip->calibrate_signal == 0)
+ writew(readw(chip->SMA + SMA_wCurrHostStatusFlags)
+ | 0x0001, chip->SMA + SMA_wCurrHostStatusFlags);
+ else
+ writew(readw(chip->SMA + SMA_wCurrHostStatusFlags)
+ & ~0x0001, chip->SMA + SMA_wCurrHostStatusFlags);
+ if (snd_msnd_send_word(chip, 0, 0, HDEXAR_CAL_A_TO_D) == 0 &&
+ snd_msnd_send_dsp_cmd_chk(chip, HDEX_AUX_REQ) == 0) {
+ schedule_timeout_interruptible(msecs_to_jiffies(333));
+ return 0;
+ }
+ printk(KERN_WARNING LOGNAME ": ADC calibration failed\n");
+ return -EIO;
+}
+
+/*
+ * ALSA callback function, called when attempting to open the MIDI device.
+ */
+static int snd_msnd_mpu401_open(struct snd_mpu401 *mpu)
+{
+ snd_msnd_enable_irq(mpu->private_data);
+ snd_msnd_send_dsp_cmd(mpu->private_data, HDEX_MIDI_IN_START);
+ return 0;
+}
+
+static void snd_msnd_mpu401_close(struct snd_mpu401 *mpu)
+{
+ snd_msnd_send_dsp_cmd(mpu->private_data, HDEX_MIDI_IN_STOP);
+ snd_msnd_disable_irq(mpu->private_data);
+}
+
+static long mpu_io[SNDRV_CARDS] = SNDRV_DEFAULT_PORT;
+static int mpu_irq[SNDRV_CARDS] = SNDRV_DEFAULT_IRQ;
+
+static int __devinit snd_msnd_attach(struct snd_card *card)
+{
+ struct snd_msnd *chip = card->private_data;
+ int err;
+ static struct snd_device_ops ops = {
+ .dev_free = snd_msnd_dev_free,
+ };
+
+ err = request_irq(chip->irq, snd_msnd_interrupt, 0, card->shortname,
+ chip);
+ if (err < 0) {
+ printk(KERN_ERR LOGNAME ": Couldn't grab IRQ %d\n", chip->irq);
+ return err;
+ }
+ request_region(chip->io, DSP_NUMIO, card->shortname);
+
+ if (!request_mem_region(chip->base, BUFFSIZE, card->shortname)) {
+ printk(KERN_ERR LOGNAME
+ ": unable to grab memory region 0x%lx-0x%lx\n",
+ chip->base, chip->base + BUFFSIZE - 1);
+ release_region(chip->io, DSP_NUMIO);
+ free_irq(chip->irq, chip);
+ return -EBUSY;
+ }
+ chip->mappedbase = ioremap_nocache(chip->base, 0x8000);
+ if (!chip->mappedbase) {
+ printk(KERN_ERR LOGNAME
+ ": unable to map memory region 0x%lx-0x%lx\n",
+ chip->base, chip->base + BUFFSIZE - 1);
+ err = -EIO;
+ goto err_release_region;
+ }
+
+ err = snd_msnd_dsp_full_reset(card);
+ if (err < 0)
+ goto err_release_region;
+
+ /* Register device */
+ err = snd_device_new(card, SNDRV_DEV_LOWLEVEL, chip, &ops);
+ if (err < 0)
+ goto err_release_region;
+
+ err = snd_msnd_pcm(card, 0, NULL);
+ if (err < 0) {
+ printk(KERN_ERR LOGNAME ": error creating new PCM device\n");
+ goto err_release_region;
+ }
+
+ err = snd_msndmix_new(card);
+ if (err < 0) {
+ printk(KERN_ERR LOGNAME ": error creating new Mixer device\n");
+ goto err_release_region;
+ }
+
+
+ if (mpu_io[0] != SNDRV_AUTO_PORT) {
+ struct snd_mpu401 *mpu;
+
+ err = snd_mpu401_uart_new(card, 0, MPU401_HW_MPU401,
+ mpu_io[0],
+ MPU401_MODE_INPUT |
+ MPU401_MODE_OUTPUT,
+ mpu_irq[0], IRQF_DISABLED,
+ &chip->rmidi);
+ if (err < 0) {
+ printk(KERN_ERR LOGNAME
+ ": error creating new Midi device\n");
+ goto err_release_region;
+ }
+ mpu = chip->rmidi->private_data;
+
+ mpu->open_input = snd_msnd_mpu401_open;
+ mpu->close_input = snd_msnd_mpu401_close;
+ mpu->private_data = chip;
+ }
+
+ disable_irq(chip->irq);
+ snd_msnd_calibrate_adc(chip, chip->play_sample_rate);
+ snd_msndmix_force_recsrc(chip, 0);
+
+ err = snd_card_register(card);
+ if (err < 0)
+ goto err_release_region;
+
+ return 0;
+
+err_release_region:
+ if (chip->mappedbase)
+ iounmap(chip->mappedbase);
+ release_mem_region(chip->base, BUFFSIZE);
+ release_region(chip->io, DSP_NUMIO);
+ free_irq(chip->irq, chip);
+ return err;
+}
+
+
+static void __devexit snd_msnd_unload(struct snd_card *card)
+{
+ struct snd_msnd *chip = card->private_data;
+
+ iounmap(chip->mappedbase);
+ release_mem_region(chip->base, BUFFSIZE);
+ release_region(chip->io, DSP_NUMIO);
+ free_irq(chip->irq, chip);
+ snd_card_free(card);
+}
+
+#ifndef MSND_CLASSIC
+
+/* Pinnacle/Fiji Logical Device Configuration */
+
+static int __devinit snd_msnd_write_cfg(int cfg, int reg, int value)
+{
+ outb(reg, cfg);
+ outb(value, cfg + 1);
+ if (value != inb(cfg + 1)) {
+ printk(KERN_ERR LOGNAME ": snd_msnd_write_cfg: I/O error\n");
+ return -EIO;
+ }
+ return 0;
+}
+
+static int __devinit snd_msnd_write_cfg_io0(int cfg, int num, u16 io)
+{
+ if (snd_msnd_write_cfg(cfg, IREG_LOGDEVICE, num))
+ return -EIO;
+ if (snd_msnd_write_cfg(cfg, IREG_IO0_BASEHI, HIBYTE(io)))
+ return -EIO;
+ if (snd_msnd_write_cfg(cfg, IREG_IO0_BASELO, LOBYTE(io)))
+ return -EIO;
+ return 0;
+}
+
+static int __devinit snd_msnd_write_cfg_io1(int cfg, int num, u16 io)
+{
+ if (snd_msnd_write_cfg(cfg, IREG_LOGDEVICE, num))
+ return -EIO;
+ if (snd_msnd_write_cfg(cfg, IREG_IO1_BASEHI, HIBYTE(io)))
+ return -EIO;
+ if (snd_msnd_write_cfg(cfg, IREG_IO1_BASELO, LOBYTE(io)))
+ return -EIO;
+ return 0;
+}
+
+static int __devinit snd_msnd_write_cfg_irq(int cfg, int num, u16 irq)
+{
+ if (snd_msnd_write_cfg(cfg, IREG_LOGDEVICE, num))
+ return -EIO;
+ if (snd_msnd_write_cfg(cfg, IREG_IRQ_NUMBER, LOBYTE(irq)))
+ return -EIO;
+ if (snd_msnd_write_cfg(cfg, IREG_IRQ_TYPE, IRQTYPE_EDGE))
+ return -EIO;
+ return 0;
+}
+
+static int __devinit snd_msnd_write_cfg_mem(int cfg, int num, int mem)
+{
+ u16 wmem;
+
+ mem >>= 8;
+ wmem = (u16)(mem & 0xfff);
+ if (snd_msnd_write_cfg(cfg, IREG_LOGDEVICE, num))
+ return -EIO;
+ if (snd_msnd_write_cfg(cfg, IREG_MEMBASEHI, HIBYTE(wmem)))
+ return -EIO;
+ if (snd_msnd_write_cfg(cfg, IREG_MEMBASELO, LOBYTE(wmem)))
+ return -EIO;
+ if (wmem && snd_msnd_write_cfg(cfg, IREG_MEMCONTROL,
+ MEMTYPE_HIADDR | MEMTYPE_16BIT))
+ return -EIO;
+ return 0;
+}
+
+static int __devinit snd_msnd_activate_logical(int cfg, int num)
+{
+ if (snd_msnd_write_cfg(cfg, IREG_LOGDEVICE, num))
+ return -EIO;
+ if (snd_msnd_write_cfg(cfg, IREG_ACTIVATE, LD_ACTIVATE))
+ return -EIO;
+ return 0;
+}
+
+static int __devinit snd_msnd_write_cfg_logical(int cfg, int num, u16 io0,
+ u16 io1, u16 irq, int mem)
+{
+ if (snd_msnd_write_cfg(cfg, IREG_LOGDEVICE, num))
+ return -EIO;
+ if (snd_msnd_write_cfg_io0(cfg, num, io0))
+ return -EIO;
+ if (snd_msnd_write_cfg_io1(cfg, num, io1))
+ return -EIO;
+ if (snd_msnd_write_cfg_irq(cfg, num, irq))
+ return -EIO;
+ if (snd_msnd_write_cfg_mem(cfg, num, mem))
+ return -EIO;
+ if (snd_msnd_activate_logical(cfg, num))
+ return -EIO;
+ return 0;
+}
+
+static int __devinit snd_msnd_pinnacle_cfg_reset(int cfg)
+{
+ int i;
+
+ /* Reset devices if told to */
+ printk(KERN_INFO LOGNAME ": Resetting all devices\n");
+ for (i = 0; i < 4; ++i)
+ if (snd_msnd_write_cfg_logical(cfg, i, 0, 0, 0, 0))
+ return -EIO;
+
+ return 0;
+}
+#endif
+
+static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX; /* Index 0-MAX */
+static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR; /* ID for this card */
+
+module_param_array(index, int, NULL, S_IRUGO);
+MODULE_PARM_DESC(index, "Index value for msnd_pinnacle soundcard.");
+module_param_array(id, charp, NULL, S_IRUGO);
+MODULE_PARM_DESC(id, "ID string for msnd_pinnacle soundcard.");
+
+static long io[SNDRV_CARDS] = SNDRV_DEFAULT_PORT;
+static int irq[SNDRV_CARDS] = SNDRV_DEFAULT_IRQ;
+static long mem[SNDRV_CARDS] = SNDRV_DEFAULT_PORT;
+
+static long cfg[SNDRV_CARDS] = SNDRV_DEFAULT_PORT;
+
+#ifndef MSND_CLASSIC
+/* Extra Peripheral Configuration (Default: Disable) */
+static long ide_io0[SNDRV_CARDS] = SNDRV_DEFAULT_PORT;
+static long ide_io1[SNDRV_CARDS] = SNDRV_DEFAULT_PORT;
+static int ide_irq[SNDRV_CARDS] = SNDRV_DEFAULT_IRQ;
+
+static long joystick_io[SNDRV_CARDS] = SNDRV_DEFAULT_PORT;
+/* If we have the digital daugherboard... */
+static int digital[SNDRV_CARDS];
+
+/* Extra Peripheral Configuration */
+static int reset[SNDRV_CARDS];
+#endif
+
+static int write_ndelay[SNDRV_CARDS] = { [0 ... (SNDRV_CARDS-1)] = 1 };
+
+static int calibrate_signal;
+
+#ifdef CONFIG_PNP
+static int isapnp[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE_PNP;
+module_param_array(isapnp, bool, NULL, 0444);
+MODULE_PARM_DESC(isapnp, "ISA PnP detection for specified soundcard.");
+#define has_isapnp(x) isapnp[x]
+#else
+#define has_isapnp(x) 0
+#endif
+
+MODULE_AUTHOR("Karsten Wiese <annabellesgarden@yahoo.de>");
+MODULE_DESCRIPTION("Turtle Beach " LONGNAME " Linux Driver");
+MODULE_LICENSE("GPL");
+MODULE_FIRMWARE(INITCODEFILE);
+MODULE_FIRMWARE(PERMCODEFILE);
+
+module_param_array(io, long, NULL, S_IRUGO);
+MODULE_PARM_DESC(io, "IO port #");
+module_param_array(irq, int, NULL, S_IRUGO);
+module_param_array(mem, long, NULL, S_IRUGO);
+module_param_array(write_ndelay, int, NULL, S_IRUGO);
+module_param(calibrate_signal, int, S_IRUGO);
+#ifndef MSND_CLASSIC
+module_param_array(digital, int, NULL, S_IRUGO);
+module_param_array(cfg, long, NULL, S_IRUGO);
+module_param_array(reset, int, 0, S_IRUGO);
+module_param_array(mpu_io, long, NULL, S_IRUGO);
+module_param_array(mpu_irq, int, NULL, S_IRUGO);
+module_param_array(ide_io0, long, NULL, S_IRUGO);
+module_param_array(ide_io1, long, NULL, S_IRUGO);
+module_param_array(ide_irq, int, NULL, S_IRUGO);
+module_param_array(joystick_io, long, NULL, S_IRUGO);
+#endif
+
+
+static int __devinit snd_msnd_isa_match(struct device *pdev, unsigned int i)
+{
+ if (io[i] == SNDRV_AUTO_PORT)
+ return 0;
+
+ if (irq[i] == SNDRV_AUTO_PORT || mem[i] == SNDRV_AUTO_PORT) {
+ printk(KERN_WARNING LOGNAME ": io, irq and mem must be set\n");
+ return 0;
+ }
+
+#ifdef MSND_CLASSIC
+ if (!(io[i] == 0x290 ||
+ io[i] == 0x260 ||
+ io[i] == 0x250 ||
+ io[i] == 0x240 ||
+ io[i] == 0x230 ||
+ io[i] == 0x220 ||
+ io[i] == 0x210 ||
+ io[i] == 0x3e0)) {
+ printk(KERN_ERR LOGNAME ": \"io\" - DSP I/O base must be set "
+ " to 0x210, 0x220, 0x230, 0x240, 0x250, 0x260, 0x290, "
+ "or 0x3E0\n");
+ return 0;
+ }
+#else
+ if (io[i] < 0x100 || io[i] > 0x3e0 || (io[i] % 0x10) != 0) {
+ printk(KERN_ERR LOGNAME
+ ": \"io\" - DSP I/O base must within the range 0x100 "
+ "to 0x3E0 and must be evenly divisible by 0x10\n");
+ return 0;
+ }
+#endif /* MSND_CLASSIC */
+
+ if (!(irq[i] == 5 ||
+ irq[i] == 7 ||
+ irq[i] == 9 ||
+ irq[i] == 10 ||
+ irq[i] == 11 ||
+ irq[i] == 12)) {
+ printk(KERN_ERR LOGNAME
+ ": \"irq\" - must be set to 5, 7, 9, 10, 11 or 12\n");
+ return 0;
+ }
+
+ if (!(mem[i] == 0xb0000 ||
+ mem[i] == 0xc8000 ||
+ mem[i] == 0xd0000 ||
+ mem[i] == 0xd8000 ||
+ mem[i] == 0xe0000 ||
+ mem[i] == 0xe8000)) {
+ printk(KERN_ERR LOGNAME ": \"mem\" - must be set to "
+ "0xb0000, 0xc8000, 0xd0000, 0xd8000, 0xe0000 or "
+ "0xe8000\n");
+ return 0;
+ }
+
+#ifndef MSND_CLASSIC
+ if (cfg[i] == SNDRV_AUTO_PORT) {
+ printk(KERN_INFO LOGNAME ": Assuming PnP mode\n");
+ } else if (cfg[i] != 0x250 && cfg[i] != 0x260 && cfg[i] != 0x270) {
+ printk(KERN_INFO LOGNAME
+ ": Config port must be 0x250, 0x260 or 0x270 "
+ "(or unspecified for PnP mode)\n");
+ return 0;
+ }
+#endif /* MSND_CLASSIC */
+
+ return 1;
+}
+
+static int __devinit snd_msnd_isa_probe(struct device *pdev, unsigned int idx)
+{
+ int err;
+ struct snd_card *card;
+ struct snd_msnd *chip;
+
+ if (has_isapnp(idx) || cfg[idx] == SNDRV_AUTO_PORT) {
+ printk(KERN_INFO LOGNAME ": Assuming PnP mode\n");
+ return -ENODEV;
+ }
+
+ err = snd_card_create(index[idx], id[idx], THIS_MODULE,
+ sizeof(struct snd_msnd), &card);
+ if (err < 0)
+ return err;
+
+ snd_card_set_dev(card, pdev);
+ chip = card->private_data;
+ chip->card = card;
+
+#ifdef MSND_CLASSIC
+ switch (irq[idx]) {
+ case 5:
+ chip->irqid = HPIRQ_5; break;
+ case 7:
+ chip->irqid = HPIRQ_7; break;
+ case 9:
+ chip->irqid = HPIRQ_9; break;
+ case 10:
+ chip->irqid = HPIRQ_10; break;
+ case 11:
+ chip->irqid = HPIRQ_11; break;
+ case 12:
+ chip->irqid = HPIRQ_12; break;
+ }
+
+ switch (mem[idx]) {
+ case 0xb0000:
+ chip->memid = HPMEM_B000; break;
+ case 0xc8000:
+ chip->memid = HPMEM_C800; break;
+ case 0xd0000:
+ chip->memid = HPMEM_D000; break;
+ case 0xd8000:
+ chip->memid = HPMEM_D800; break;
+ case 0xe0000:
+ chip->memid = HPMEM_E000; break;
+ case 0xe8000:
+ chip->memid = HPMEM_E800; break;
+ }
+#else
+ printk(KERN_INFO LOGNAME ": Non-PnP mode: configuring at port 0x%lx\n",
+ cfg[idx]);
+
+ if (!request_region(cfg[idx], 2, "Pinnacle/Fiji Config")) {
+ printk(KERN_ERR LOGNAME ": Config port 0x%lx conflict\n",
+ cfg[idx]);
+ snd_card_free(card);
+ return -EIO;
+ }
+ if (reset[idx])
+ if (snd_msnd_pinnacle_cfg_reset(cfg[idx])) {
+ err = -EIO;
+ goto cfg_error;
+ }
+
+ /* DSP */
+ err = snd_msnd_write_cfg_logical(cfg[idx], 0,
+ io[idx], 0,
+ irq[idx], mem[idx]);
+
+ if (err)
+ goto cfg_error;
+
+ /* The following are Pinnacle specific */
+
+ /* MPU */
+ if (mpu_io[idx] != SNDRV_AUTO_PORT
+ && mpu_irq[idx] != SNDRV_AUTO_IRQ) {
+ printk(KERN_INFO LOGNAME
+ ": Configuring MPU to I/O 0x%lx IRQ %d\n",
+ mpu_io[idx], mpu_irq[idx]);
+ err = snd_msnd_write_cfg_logical(cfg[idx], 1,
+ mpu_io[idx], 0,
+ mpu_irq[idx], 0);
+
+ if (err)
+ goto cfg_error;
+ }
+
+ /* IDE */
+ if (ide_io0[idx] != SNDRV_AUTO_PORT
+ && ide_io1[idx] != SNDRV_AUTO_PORT
+ && ide_irq[idx] != SNDRV_AUTO_IRQ) {
+ printk(KERN_INFO LOGNAME
+ ": Configuring IDE to I/O 0x%lx, 0x%lx IRQ %d\n",
+ ide_io0[idx], ide_io1[idx], ide_irq[idx]);
+ err = snd_msnd_write_cfg_logical(cfg[idx], 2,
+ ide_io0[idx], ide_io1[idx],
+ ide_irq[idx], 0);
+
+ if (err)
+ goto cfg_error;
+ }
+
+ /* Joystick */
+ if (joystick_io[idx] != SNDRV_AUTO_PORT) {
+ printk(KERN_INFO LOGNAME
+ ": Configuring joystick to I/O 0x%lx\n",
+ joystick_io[idx]);
+ err = snd_msnd_write_cfg_logical(cfg[idx], 3,
+ joystick_io[idx], 0,
+ 0, 0);
+
+ if (err)
+ goto cfg_error;
+ }
+ release_region(cfg[idx], 2);
+
+#endif /* MSND_CLASSIC */
+
+ set_default_audio_parameters(chip);
+#ifdef MSND_CLASSIC
+ chip->type = msndClassic;
+#else
+ chip->type = msndPinnacle;
+#endif
+ chip->io = io[idx];
+ chip->irq = irq[idx];
+ chip->base = mem[idx];
+
+ chip->calibrate_signal = calibrate_signal ? 1 : 0;
+ chip->recsrc = 0;
+ chip->dspq_data_buff = DSPQ_DATA_BUFF;
+ chip->dspq_buff_size = DSPQ_BUFF_SIZE;
+ if (write_ndelay[idx])
+ clear_bit(F_DISABLE_WRITE_NDELAY, &chip->flags);
+ else
+ set_bit(F_DISABLE_WRITE_NDELAY, &chip->flags);
+#ifndef MSND_CLASSIC
+ if (digital[idx])
+ set_bit(F_HAVEDIGITAL, &chip->flags);
+#endif
+ spin_lock_init(&chip->lock);
+ err = snd_msnd_probe(card);
+ if (err < 0) {
+ printk(KERN_ERR LOGNAME ": Probe failed\n");
+ snd_card_free(card);
+ return err;
+ }
+
+ err = snd_msnd_attach(card);
+ if (err < 0) {
+ printk(KERN_ERR LOGNAME ": Attach failed\n");
+ snd_card_free(card);
+ return err;
+ }
+ dev_set_drvdata(pdev, card);
+
+ return 0;
+
+#ifndef MSND_CLASSIC
+cfg_error:
+ release_region(cfg[idx], 2);
+ snd_card_free(card);
+ return err;
+#endif
+}
+
+static int __devexit snd_msnd_isa_remove(struct device *pdev, unsigned int dev)
+{
+ snd_msnd_unload(dev_get_drvdata(pdev));
+ dev_set_drvdata(pdev, NULL);
+ return 0;
+}
+
+#define DEV_NAME "msnd-pinnacle"
+
+static struct isa_driver snd_msnd_driver = {
+ .match = snd_msnd_isa_match,
+ .probe = snd_msnd_isa_probe,
+ .remove = __devexit_p(snd_msnd_isa_remove),
+ /* FIXME: suspend, resume */
+ .driver = {
+ .name = DEV_NAME
+ },
+};
+
+#ifdef CONFIG_PNP
+static int __devinit snd_msnd_pnp_detect(struct pnp_card_link *pcard,
+ const struct pnp_card_device_id *pid)
+{
+ static int idx;
+ struct pnp_dev *pnp_dev;
+ struct pnp_dev *mpu_dev;
+ struct snd_card *card;
+ struct snd_msnd *chip;
+ int ret;
+
+ for ( ; idx < SNDRV_CARDS; idx++) {
+ if (has_isapnp(idx))
+ break;
+ }
+ if (idx >= SNDRV_CARDS)
+ return -ENODEV;
+
+ /*
+ * Check that we still have room for another sound card ...
+ */
+ pnp_dev = pnp_request_card_device(pcard, pid->devs[0].id, NULL);
+ if (!pnp_dev)
+ return -ENODEV;
+
+ mpu_dev = pnp_request_card_device(pcard, pid->devs[1].id, NULL);
+ if (!mpu_dev)
+ return -ENODEV;
+
+ if (!pnp_is_active(pnp_dev) && pnp_activate_dev(pnp_dev) < 0) {
+ printk(KERN_INFO "msnd_pinnacle: device is inactive\n");
+ return -EBUSY;
+ }
+
+ if (!pnp_is_active(mpu_dev) && pnp_activate_dev(mpu_dev) < 0) {
+ printk(KERN_INFO "msnd_pinnacle: MPU device is inactive\n");
+ return -EBUSY;
+ }
+
+ /*
+ * Create a new ALSA sound card entry, in anticipation
+ * of detecting our hardware ...
+ */
+ ret = snd_card_create(index[idx], id[idx], THIS_MODULE,
+ sizeof(struct snd_msnd), &card);
+ if (ret < 0)
+ return ret;
+
+ chip = card->private_data;
+ chip->card = card;
+ snd_card_set_dev(card, &pcard->card->dev);
+
+ /*
+ * Read the correct parameters off the ISA PnP bus ...
+ */
+ io[idx] = pnp_port_start(pnp_dev, 0);
+ irq[idx] = pnp_irq(pnp_dev, 0);
+ mem[idx] = pnp_mem_start(pnp_dev, 0);
+ mpu_io[idx] = pnp_port_start(mpu_dev, 0);
+ mpu_irq[idx] = pnp_irq(mpu_dev, 0);
+
+ set_default_audio_parameters(chip);
+#ifdef MSND_CLASSIC
+ chip->type = msndClassic;
+#else
+ chip->type = msndPinnacle;
+#endif
+ chip->io = io[idx];
+ chip->irq = irq[idx];
+ chip->base = mem[idx];
+
+ chip->calibrate_signal = calibrate_signal ? 1 : 0;
+ chip->recsrc = 0;
+ chip->dspq_data_buff = DSPQ_DATA_BUFF;
+ chip->dspq_buff_size = DSPQ_BUFF_SIZE;
+ if (write_ndelay[idx])
+ clear_bit(F_DISABLE_WRITE_NDELAY, &chip->flags);
+ else
+ set_bit(F_DISABLE_WRITE_NDELAY, &chip->flags);
+#ifndef MSND_CLASSIC
+ if (digital[idx])
+ set_bit(F_HAVEDIGITAL, &chip->flags);
+#endif
+ spin_lock_init(&chip->lock);
+ ret = snd_msnd_probe(card);
+ if (ret < 0) {
+ printk(KERN_ERR LOGNAME ": Probe failed\n");
+ goto _release_card;
+ }
+
+ ret = snd_msnd_attach(card);
+ if (ret < 0) {
+ printk(KERN_ERR LOGNAME ": Attach failed\n");
+ goto _release_card;
+ }
+
+ pnp_set_card_drvdata(pcard, card);
+ ++idx;
+ return 0;
+
+_release_card:
+ snd_card_free(card);
+ return ret;
+}
+
+static void __devexit snd_msnd_pnp_remove(struct pnp_card_link *pcard)
+{
+ snd_msnd_unload(pnp_get_card_drvdata(pcard));
+ pnp_set_card_drvdata(pcard, NULL);
+}
+
+static int isa_registered;
+static int pnp_registered;
+
+static struct pnp_card_device_id msnd_pnpids[] = {
+ /* Pinnacle PnP */
+ { .id = "BVJ0440", .devs = { { "TBS0000" }, { "TBS0001" } } },
+ { .id = "" } /* end */
+};
+
+MODULE_DEVICE_TABLE(pnp_card, msnd_pnpids);
+
+static struct pnp_card_driver msnd_pnpc_driver = {
+ .flags = PNP_DRIVER_RES_DO_NOT_CHANGE,
+ .name = "msnd_pinnacle",
+ .id_table = msnd_pnpids,
+ .probe = snd_msnd_pnp_detect,
+ .remove = __devexit_p(snd_msnd_pnp_remove),
+};
+#endif /* CONFIG_PNP */
+
+static int __init snd_msnd_init(void)
+{
+ int err;
+
+ err = isa_register_driver(&snd_msnd_driver, SNDRV_CARDS);
+#ifdef CONFIG_PNP
+ if (!err)
+ isa_registered = 1;
+
+ err = pnp_register_card_driver(&msnd_pnpc_driver);
+ if (!err)
+ pnp_registered = 1;
+
+ if (isa_registered)
+ err = 0;
+#endif
+ return err;
+}
+
+static void __exit snd_msnd_exit(void)
+{
+#ifdef CONFIG_PNP
+ if (pnp_registered)
+ pnp_unregister_card_driver(&msnd_pnpc_driver);
+ if (isa_registered)
+#endif
+ isa_unregister_driver(&snd_msnd_driver);
+}
+
+module_init(snd_msnd_init);
+module_exit(snd_msnd_exit);
+
diff --git a/sound/isa/msnd/msnd_pinnacle.h b/sound/isa/msnd/msnd_pinnacle.h
new file mode 100644
index 00000000000..48318d1ee34
--- /dev/null
+++ b/sound/isa/msnd/msnd_pinnacle.h
@@ -0,0 +1,181 @@
+/*********************************************************************
+ *
+ * msnd_pinnacle.h
+ *
+ * Turtle Beach MultiSound Sound Card Driver for Linux
+ *
+ * Some parts of this header file were derived from the Turtle Beach
+ * MultiSound Driver Development Kit.
+ *
+ * Copyright (C) 1998 Andrew Veliath
+ * Copyright (C) 1993 Turtle Beach Systems, Inc.
+ *
+ * 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ ********************************************************************/
+#ifndef __MSND_PINNACLE_H
+#define __MSND_PINNACLE_H
+
+#define DSP_NUMIO 0x08
+
+#define IREG_LOGDEVICE 0x07
+#define IREG_ACTIVATE 0x30
+#define LD_ACTIVATE 0x01
+#define LD_DISACTIVATE 0x00
+#define IREG_EECONTROL 0x3F
+#define IREG_MEMBASEHI 0x40
+#define IREG_MEMBASELO 0x41
+#define IREG_MEMCONTROL 0x42
+#define IREG_MEMRANGEHI 0x43
+#define IREG_MEMRANGELO 0x44
+#define MEMTYPE_8BIT 0x00
+#define MEMTYPE_16BIT 0x02
+#define MEMTYPE_RANGE 0x00
+#define MEMTYPE_HIADDR 0x01
+#define IREG_IO0_BASEHI 0x60
+#define IREG_IO0_BASELO 0x61
+#define IREG_IO1_BASEHI 0x62
+#define IREG_IO1_BASELO 0x63
+#define IREG_IRQ_NUMBER 0x70
+#define IREG_IRQ_TYPE 0x71
+#define IRQTYPE_HIGH 0x02
+#define IRQTYPE_LOW 0x00
+#define IRQTYPE_LEVEL 0x01
+#define IRQTYPE_EDGE 0x00
+
+#define HP_DSPR 0x04
+#define HP_BLKS 0x04
+
+#define HPDSPRESET_OFF 2
+#define HPDSPRESET_ON 0
+
+#define HPBLKSEL_0 2
+#define HPBLKSEL_1 3
+
+#define HIMT_DAT_OFF 0x03
+
+#define HIDSP_PLAY_UNDER 0x00
+#define HIDSP_INT_PLAY_UNDER 0x01
+#define HIDSP_SSI_TX_UNDER 0x02
+#define HIDSP_RECQ_OVERFLOW 0x08
+#define HIDSP_INT_RECORD_OVER 0x09
+#define HIDSP_SSI_RX_OVERFLOW 0x0a
+
+#define HIDSP_MIDI_IN_OVER 0x10
+
+#define HIDSP_MIDI_FRAME_ERR 0x11
+#define HIDSP_MIDI_PARITY_ERR 0x12
+#define HIDSP_MIDI_OVERRUN_ERR 0x13
+
+#define HIDSP_INPUT_CLIPPING 0x20
+#define HIDSP_MIX_CLIPPING 0x30
+#define HIDSP_DAT_IN_OFF 0x21
+
+#define TIME_PRO_RESET_DONE 0x028A
+#define TIME_PRO_SYSEX 0x001E
+#define TIME_PRO_RESET 0x0032
+
+#define DAR_BUFF_SIZE 0x1000
+
+#define MIDQ_BUFF_SIZE 0x800
+#define DSPQ_BUFF_SIZE 0x5A0
+
+#define DSPQ_DATA_BUFF 0x7860
+
+#define MOP_WAVEHDR 0
+#define MOP_EXTOUT 1
+#define MOP_HWINIT 0xfe
+#define MOP_NONE 0xff
+#define MOP_MAX 1
+
+#define MIP_EXTIN 0
+#define MIP_WAVEHDR 1
+#define MIP_HWINIT 0xfe
+#define MIP_MAX 1
+
+/* Pinnacle/Fiji SMA Common Data */
+#define SMA_wCurrPlayBytes 0x0000
+#define SMA_wCurrRecordBytes 0x0002
+#define SMA_wCurrPlayVolLeft 0x0004
+#define SMA_wCurrPlayVolRight 0x0006
+#define SMA_wCurrInVolLeft 0x0008
+#define SMA_wCurrInVolRight 0x000a
+#define SMA_wCurrMHdrVolLeft 0x000c
+#define SMA_wCurrMHdrVolRight 0x000e
+#define SMA_dwCurrPlayPitch 0x0010
+#define SMA_dwCurrPlayRate 0x0014
+#define SMA_wCurrMIDIIOPatch 0x0018
+#define SMA_wCurrPlayFormat 0x001a
+#define SMA_wCurrPlaySampleSize 0x001c
+#define SMA_wCurrPlayChannels 0x001e
+#define SMA_wCurrPlaySampleRate 0x0020
+#define SMA_wCurrRecordFormat 0x0022
+#define SMA_wCurrRecordSampleSize 0x0024
+#define SMA_wCurrRecordChannels 0x0026
+#define SMA_wCurrRecordSampleRate 0x0028
+#define SMA_wCurrDSPStatusFlags 0x002a
+#define SMA_wCurrHostStatusFlags 0x002c
+#define SMA_wCurrInputTagBits 0x002e
+#define SMA_wCurrLeftPeak 0x0030
+#define SMA_wCurrRightPeak 0x0032
+#define SMA_bMicPotPosLeft 0x0034
+#define SMA_bMicPotPosRight 0x0035
+#define SMA_bMicPotMaxLeft 0x0036
+#define SMA_bMicPotMaxRight 0x0037
+#define SMA_bInPotPosLeft 0x0038
+#define SMA_bInPotPosRight 0x0039
+#define SMA_bAuxPotPosLeft 0x003a
+#define SMA_bAuxPotPosRight 0x003b
+#define SMA_bInPotMaxLeft 0x003c
+#define SMA_bInPotMaxRight 0x003d
+#define SMA_bAuxPotMaxLeft 0x003e
+#define SMA_bAuxPotMaxRight 0x003f
+#define SMA_bInPotMaxMethod 0x0040
+#define SMA_bAuxPotMaxMethod 0x0041
+#define SMA_wCurrMastVolLeft 0x0042
+#define SMA_wCurrMastVolRight 0x0044
+#define SMA_wCalFreqAtoD 0x0046
+#define SMA_wCurrAuxVolLeft 0x0048
+#define SMA_wCurrAuxVolRight 0x004a
+#define SMA_wCurrPlay1VolLeft 0x004c
+#define SMA_wCurrPlay1VolRight 0x004e
+#define SMA_wCurrPlay2VolLeft 0x0050
+#define SMA_wCurrPlay2VolRight 0x0052
+#define SMA_wCurrPlay3VolLeft 0x0054
+#define SMA_wCurrPlay3VolRight 0x0056
+#define SMA_wCurrPlay4VolLeft 0x0058
+#define SMA_wCurrPlay4VolRight 0x005a
+#define SMA_wCurrPlay1PeakLeft 0x005c
+#define SMA_wCurrPlay1PeakRight 0x005e
+#define SMA_wCurrPlay2PeakLeft 0x0060
+#define SMA_wCurrPlay2PeakRight 0x0062
+#define SMA_wCurrPlay3PeakLeft 0x0064
+#define SMA_wCurrPlay3PeakRight 0x0066
+#define SMA_wCurrPlay4PeakLeft 0x0068
+#define SMA_wCurrPlay4PeakRight 0x006a
+#define SMA_wCurrPlayPeakLeft 0x006c
+#define SMA_wCurrPlayPeakRight 0x006e
+#define SMA_wCurrDATSR 0x0070
+#define SMA_wCurrDATRXCHNL 0x0072
+#define SMA_wCurrDATTXCHNL 0x0074
+#define SMA_wCurrDATRXRate 0x0076
+#define SMA_dwDSPPlayCount 0x0078
+#define SMA__size 0x007c
+
+#define INITCODEFILE "turtlebeach/pndspini.bin"
+#define PERMCODEFILE "turtlebeach/pndsperm.bin"
+#define LONGNAME "MultiSound (Pinnacle/Fiji)"
+
+#endif /* __MSND_PINNACLE_H */
diff --git a/sound/isa/msnd/msnd_pinnacle_mixer.c b/sound/isa/msnd/msnd_pinnacle_mixer.c
new file mode 100644
index 00000000000..494058a1a50
--- /dev/null
+++ b/sound/isa/msnd/msnd_pinnacle_mixer.c
@@ -0,0 +1,343 @@
+/***************************************************************************
+ msnd_pinnacle_mixer.c - description
+ -------------------
+ begin : Fre Jun 7 2002
+ copyright : (C) 2002 by karsten wiese
+ email : annabellesgarden@yahoo.de
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * 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. *
+ * *
+ ***************************************************************************/
+
+#include <linux/io.h>
+
+#include <sound/core.h>
+#include <sound/control.h>
+#include "msnd.h"
+#include "msnd_pinnacle.h"
+
+
+#define MSND_MIXER_VOLUME 0
+#define MSND_MIXER_PCM 1
+#define MSND_MIXER_AUX 2 /* Input source 1 (aux1) */
+#define MSND_MIXER_IMIX 3 /* Recording monitor */
+#define MSND_MIXER_SYNTH 4
+#define MSND_MIXER_SPEAKER 5
+#define MSND_MIXER_LINE 6
+#define MSND_MIXER_MIC 7
+#define MSND_MIXER_RECLEV 11 /* Recording level */
+#define MSND_MIXER_IGAIN 12 /* Input gain */
+#define MSND_MIXER_OGAIN 13 /* Output gain */
+#define MSND_MIXER_DIGITAL 17 /* Digital (input) 1 */
+
+/* Device mask bits */
+
+#define MSND_MASK_VOLUME (1 << MSND_MIXER_VOLUME)
+#define MSND_MASK_SYNTH (1 << MSND_MIXER_SYNTH)
+#define MSND_MASK_PCM (1 << MSND_MIXER_PCM)
+#define MSND_MASK_SPEAKER (1 << MSND_MIXER_SPEAKER)
+#define MSND_MASK_LINE (1 << MSND_MIXER_LINE)
+#define MSND_MASK_MIC (1 << MSND_MIXER_MIC)
+#define MSND_MASK_IMIX (1 << MSND_MIXER_IMIX)
+#define MSND_MASK_RECLEV (1 << MSND_MIXER_RECLEV)
+#define MSND_MASK_IGAIN (1 << MSND_MIXER_IGAIN)
+#define MSND_MASK_OGAIN (1 << MSND_MIXER_OGAIN)
+#define MSND_MASK_AUX (1 << MSND_MIXER_AUX)
+#define MSND_MASK_DIGITAL (1 << MSND_MIXER_DIGITAL)
+
+static int snd_msndmix_info_mux(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_info *uinfo)
+{
+ static char *texts[3] = {
+ "Analog", "MASS", "SPDIF",
+ };
+ struct snd_msnd *chip = snd_kcontrol_chip(kcontrol);
+ unsigned items = test_bit(F_HAVEDIGITAL, &chip->flags) ? 3 : 2;
+
+ uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
+ uinfo->count = 1;
+ uinfo->value.enumerated.items = items;
+ if (uinfo->value.enumerated.item >= items)
+ uinfo->value.enumerated.item = items - 1;
+ strcpy(uinfo->value.enumerated.name,
+ texts[uinfo->value.enumerated.item]);
+ return 0;
+}
+
+static int snd_msndmix_get_mux(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_msnd *chip = snd_kcontrol_chip(kcontrol);
+ /* MSND_MASK_IMIX is the default */
+ ucontrol->value.enumerated.item[0] = 0;
+
+ if (chip->recsrc & MSND_MASK_SYNTH) {
+ ucontrol->value.enumerated.item[0] = 1;
+ } else if ((chip->recsrc & MSND_MASK_DIGITAL) &&
+ test_bit(F_HAVEDIGITAL, &chip->flags)) {
+ ucontrol->value.enumerated.item[0] = 2;
+ }
+
+
+ return 0;
+}
+
+static int snd_msndmix_set_mux(struct snd_msnd *chip, int val)
+{
+ unsigned newrecsrc;
+ int change;
+ unsigned char msndbyte;
+
+ switch (val) {
+ case 0:
+ newrecsrc = MSND_MASK_IMIX;
+ msndbyte = HDEXAR_SET_ANA_IN;
+ break;
+ case 1:
+ newrecsrc = MSND_MASK_SYNTH;
+ msndbyte = HDEXAR_SET_SYNTH_IN;
+ break;
+ case 2:
+ newrecsrc = MSND_MASK_DIGITAL;
+ msndbyte = HDEXAR_SET_DAT_IN;
+ break;
+ default:
+ return -EINVAL;
+ }
+ change = newrecsrc != chip->recsrc;
+ if (change) {
+ change = 0;
+ if (!snd_msnd_send_word(chip, 0, 0, msndbyte))
+ if (!snd_msnd_send_dsp_cmd(chip, HDEX_AUX_REQ)) {
+ chip->recsrc = newrecsrc;
+ change = 1;
+ }
+ }
+ return change;
+}
+
+static int snd_msndmix_put_mux(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_msnd *msnd = snd_kcontrol_chip(kcontrol);
+ return snd_msndmix_set_mux(msnd, ucontrol->value.enumerated.item[0]);
+}
+
+
+static int snd_msndmix_volume_info(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_info *uinfo)
+{
+ uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
+ uinfo->count = 2;
+ uinfo->value.integer.min = 0;
+ uinfo->value.integer.max = 100;
+ return 0;
+}
+
+static int snd_msndmix_volume_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_msnd *msnd = snd_kcontrol_chip(kcontrol);
+ int addr = kcontrol->private_value;
+ unsigned long flags;
+
+ spin_lock_irqsave(&msnd->mixer_lock, flags);
+ ucontrol->value.integer.value[0] = msnd->left_levels[addr] * 100;
+ ucontrol->value.integer.value[0] /= 0xFFFF;
+ ucontrol->value.integer.value[1] = msnd->right_levels[addr] * 100;
+ ucontrol->value.integer.value[1] /= 0xFFFF;
+ spin_unlock_irqrestore(&msnd->mixer_lock, flags);
+ return 0;
+}
+
+#define update_volm(a, b) \
+ do { \
+ writew((dev->left_levels[a] >> 1) * \
+ readw(dev->SMA + SMA_wCurrMastVolLeft) / 0xffff, \
+ dev->SMA + SMA_##b##Left); \
+ writew((dev->right_levels[a] >> 1) * \
+ readw(dev->SMA + SMA_wCurrMastVolRight) / 0xffff, \
+ dev->SMA + SMA_##b##Right); \
+ } while (0);
+
+#define update_potm(d, s, ar) \
+ do { \
+ writeb((dev->left_levels[d] >> 8) * \
+ readw(dev->SMA + SMA_wCurrMastVolLeft) / 0xffff, \
+ dev->SMA + SMA_##s##Left); \
+ writeb((dev->right_levels[d] >> 8) * \
+ readw(dev->SMA + SMA_wCurrMastVolRight) / 0xffff, \
+ dev->SMA + SMA_##s##Right); \
+ if (snd_msnd_send_word(dev, 0, 0, ar) == 0) \
+ snd_msnd_send_dsp_cmd(dev, HDEX_AUX_REQ); \
+ } while (0);
+
+#define update_pot(d, s, ar) \
+ do { \
+ writeb(dev->left_levels[d] >> 8, \
+ dev->SMA + SMA_##s##Left); \
+ writeb(dev->right_levels[d] >> 8, \
+ dev->SMA + SMA_##s##Right); \
+ if (snd_msnd_send_word(dev, 0, 0, ar) == 0) \
+ snd_msnd_send_dsp_cmd(dev, HDEX_AUX_REQ); \
+ } while (0);
+
+
+static int snd_msndmix_set(struct snd_msnd *dev, int d, int left, int right)
+{
+ int bLeft, bRight;
+ int wLeft, wRight;
+ int updatemaster = 0;
+
+ if (d >= LEVEL_ENTRIES)
+ return -EINVAL;
+
+ bLeft = left * 0xff / 100;
+ wLeft = left * 0xffff / 100;
+
+ bRight = right * 0xff / 100;
+ wRight = right * 0xffff / 100;
+
+ dev->left_levels[d] = wLeft;
+ dev->right_levels[d] = wRight;
+
+ switch (d) {
+ /* master volume unscaled controls */
+ case MSND_MIXER_LINE: /* line pot control */
+ /* scaled by IMIX in digital mix */
+ writeb(bLeft, dev->SMA + SMA_bInPotPosLeft);
+ writeb(bRight, dev->SMA + SMA_bInPotPosRight);
+ if (snd_msnd_send_word(dev, 0, 0, HDEXAR_IN_SET_POTS) == 0)
+ snd_msnd_send_dsp_cmd(dev, HDEX_AUX_REQ);
+ break;
+ case MSND_MIXER_MIC: /* mic pot control */
+ if (dev->type == msndClassic)
+ return -EINVAL;
+ /* scaled by IMIX in digital mix */
+ writeb(bLeft, dev->SMA + SMA_bMicPotPosLeft);
+ writeb(bRight, dev->SMA + SMA_bMicPotPosRight);
+ if (snd_msnd_send_word(dev, 0, 0, HDEXAR_MIC_SET_POTS) == 0)
+ snd_msnd_send_dsp_cmd(dev, HDEX_AUX_REQ);
+ break;
+ case MSND_MIXER_VOLUME: /* master volume */
+ writew(wLeft, dev->SMA + SMA_wCurrMastVolLeft);
+ writew(wRight, dev->SMA + SMA_wCurrMastVolRight);
+ /* fall through */
+
+ case MSND_MIXER_AUX: /* aux pot control */
+ /* scaled by master volume */
+ /* fall through */
+
+ /* digital controls */
+ case MSND_MIXER_SYNTH: /* synth vol (dsp mix) */
+ case MSND_MIXER_PCM: /* pcm vol (dsp mix) */
+ case MSND_MIXER_IMIX: /* input monitor (dsp mix) */
+ /* scaled by master volume */
+ updatemaster = 1;
+ break;
+
+ default:
+ return -EINVAL;
+ }
+
+ if (updatemaster) {
+ /* update master volume scaled controls */
+ update_volm(MSND_MIXER_PCM, wCurrPlayVol);
+ update_volm(MSND_MIXER_IMIX, wCurrInVol);
+ if (dev->type == msndPinnacle)
+ update_volm(MSND_MIXER_SYNTH, wCurrMHdrVol);
+ update_potm(MSND_MIXER_AUX, bAuxPotPos, HDEXAR_AUX_SET_POTS);
+ }
+
+ return 0;
+}
+
+static int snd_msndmix_volume_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_msnd *msnd = snd_kcontrol_chip(kcontrol);
+ int change, addr = kcontrol->private_value;
+ int left, right;
+ unsigned long flags;
+
+ left = ucontrol->value.integer.value[0] % 101;
+ right = ucontrol->value.integer.value[1] % 101;
+ spin_lock_irqsave(&msnd->mixer_lock, flags);
+ change = msnd->left_levels[addr] != left
+ || msnd->right_levels[addr] != right;
+ snd_msndmix_set(msnd, addr, left, right);
+ spin_unlock_irqrestore(&msnd->mixer_lock, flags);
+ return change;
+}
+
+
+#define DUMMY_VOLUME(xname, xindex, addr) \
+{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = xindex, \
+ .info = snd_msndmix_volume_info, \
+ .get = snd_msndmix_volume_get, .put = snd_msndmix_volume_put, \
+ .private_value = addr }
+
+
+static struct snd_kcontrol_new snd_msnd_controls[] = {
+DUMMY_VOLUME("Master Volume", 0, MSND_MIXER_VOLUME),
+DUMMY_VOLUME("PCM Volume", 0, MSND_MIXER_PCM),
+DUMMY_VOLUME("Aux Volume", 0, MSND_MIXER_AUX),
+DUMMY_VOLUME("Line Volume", 0, MSND_MIXER_LINE),
+DUMMY_VOLUME("Mic Volume", 0, MSND_MIXER_MIC),
+DUMMY_VOLUME("Monitor", 0, MSND_MIXER_IMIX),
+{
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+ .name = "Capture Source",
+ .info = snd_msndmix_info_mux,
+ .get = snd_msndmix_get_mux,
+ .put = snd_msndmix_put_mux,
+}
+};
+
+
+int __devinit snd_msndmix_new(struct snd_card *card)
+{
+ struct snd_msnd *chip = card->private_data;
+ unsigned int idx;
+ int err;
+
+ if (snd_BUG_ON(!chip))
+ return -EINVAL;
+ spin_lock_init(&chip->mixer_lock);
+ strcpy(card->mixername, "MSND Pinnacle Mixer");
+
+ for (idx = 0; idx < ARRAY_SIZE(snd_msnd_controls); idx++)
+ err = snd_ctl_add(card,
+ snd_ctl_new1(snd_msnd_controls + idx, chip));
+ if (err < 0)
+ return err;
+
+ return 0;
+}
+EXPORT_SYMBOL(snd_msndmix_new);
+
+void snd_msndmix_setup(struct snd_msnd *dev)
+{
+ update_pot(MSND_MIXER_LINE, bInPotPos, HDEXAR_IN_SET_POTS);
+ update_potm(MSND_MIXER_AUX, bAuxPotPos, HDEXAR_AUX_SET_POTS);
+ update_volm(MSND_MIXER_PCM, wCurrPlayVol);
+ update_volm(MSND_MIXER_IMIX, wCurrInVol);
+ if (dev->type == msndPinnacle) {
+ update_pot(MSND_MIXER_MIC, bMicPotPos, HDEXAR_MIC_SET_POTS);
+ update_volm(MSND_MIXER_SYNTH, wCurrMHdrVol);
+ }
+}
+EXPORT_SYMBOL(snd_msndmix_setup);
+
+int snd_msndmix_force_recsrc(struct snd_msnd *dev, int recsrc)
+{
+ dev->recsrc = -1;
+ return snd_msndmix_set_mux(dev, recsrc);
+}
+EXPORT_SYMBOL(snd_msndmix_force_recsrc);
diff --git a/sound/isa/opl3sa2.c b/sound/isa/opl3sa2.c
index b848d100186..ef95279da7a 100644
--- a/sound/isa/opl3sa2.c
+++ b/sound/isa/opl3sa2.c
@@ -179,12 +179,13 @@ static unsigned char __snd_opl3sa2_read(struct snd_opl3sa2 *chip, unsigned char
unsigned char result;
#if 0
outb(0x1d, port); /* password */
- printk("read [0x%lx] = 0x%x\n", port, inb(port));
+ printk(KERN_DEBUG "read [0x%lx] = 0x%x\n", port, inb(port));
#endif
outb(reg, chip->port); /* register */
result = inb(chip->port + 1);
#if 0
- printk("read [0x%lx] = 0x%x [0x%x]\n", port, result, inb(port));
+ printk(KERN_DEBUG "read [0x%lx] = 0x%x [0x%x]\n",
+ port, result, inb(port));
#endif
return result;
}
@@ -233,7 +234,10 @@ static int __devinit snd_opl3sa2_detect(struct snd_card *card)
snd_printk(KERN_ERR PFX "can't grab port 0x%lx\n", port);
return -EBUSY;
}
- // snd_printk("REG 0A = 0x%x\n", snd_opl3sa2_read(chip, 0x0a));
+ /*
+ snd_printk(KERN_DEBUG "REG 0A = 0x%x\n",
+ snd_opl3sa2_read(chip, 0x0a));
+ */
chip->version = 0;
tmp = snd_opl3sa2_read(chip, OPL3SA2_MISC);
if (tmp == 0xff) {
@@ -619,25 +623,28 @@ static void snd_opl3sa2_free(struct snd_card *card)
{
struct snd_opl3sa2 *chip = card->private_data;
if (chip->irq >= 0)
- free_irq(chip->irq, (void *)chip);
+ free_irq(chip->irq, card);
release_and_free_resource(chip->res_port);
}
-static struct snd_card *snd_opl3sa2_card_new(int dev)
+static int snd_opl3sa2_card_new(int dev, struct snd_card **cardp)
{
struct snd_card *card;
struct snd_opl3sa2 *chip;
+ int err;
- card = snd_card_new(index[dev], id[dev], THIS_MODULE, sizeof(struct snd_opl3sa2));
- if (card == NULL)
- return NULL;
+ err = snd_card_create(index[dev], id[dev], THIS_MODULE,
+ sizeof(struct snd_opl3sa2), &card);
+ if (err < 0)
+ return err;
strcpy(card->driver, "OPL3SA2");
- strcpy(card->shortname, "Yamaha OPL3-SA2");
+ strcpy(card->shortname, "Yamaha OPL3-SA");
chip = card->private_data;
spin_lock_init(&chip->reg_lock);
chip->irq = -1;
card->private_free = snd_opl3sa2_free;
- return card;
+ *cardp = card;
+ return 0;
}
static int __devinit snd_opl3sa2_probe(struct snd_card *card, int dev)
@@ -729,9 +736,9 @@ static int __devinit snd_opl3sa2_pnp_detect(struct pnp_dev *pdev,
if (dev >= SNDRV_CARDS)
return -ENODEV;
- card = snd_opl3sa2_card_new(dev);
- if (! card)
- return -ENOMEM;
+ err = snd_opl3sa2_card_new(dev, &card);
+ if (err < 0)
+ return err;
if ((err = snd_opl3sa2_pnp(dev, card->private_data, pdev)) < 0) {
snd_card_free(card);
return err;
@@ -795,9 +802,9 @@ static int __devinit snd_opl3sa2_pnp_cdetect(struct pnp_card_link *pcard,
if (dev >= SNDRV_CARDS)
return -ENODEV;
- card = snd_opl3sa2_card_new(dev);
- if (! card)
- return -ENOMEM;
+ err = snd_opl3sa2_card_new(dev, &card);
+ if (err < 0)
+ return err;
if ((err = snd_opl3sa2_pnp(dev, card->private_data, pdev)) < 0) {
snd_card_free(card);
return err;
@@ -876,9 +883,9 @@ static int __devinit snd_opl3sa2_isa_probe(struct device *pdev,
struct snd_card *card;
int err;
- card = snd_opl3sa2_card_new(dev);
- if (! card)
- return -ENOMEM;
+ err = snd_opl3sa2_card_new(dev, &card);
+ if (err < 0)
+ return err;
snd_card_set_dev(card, pdev);
if ((err = snd_opl3sa2_probe(card, dev)) < 0) {
snd_card_free(card);
diff --git a/sound/isa/opti9xx/miro.c b/sound/isa/opti9xx/miro.c
index 440755cc001..02e30d7c6a9 100644
--- a/sound/isa/opti9xx/miro.c
+++ b/sound/isa/opti9xx/miro.c
@@ -1228,9 +1228,10 @@ static int __devinit snd_miro_probe(struct device *devptr, unsigned int n)
struct snd_pcm *pcm;
struct snd_rawmidi *rmidi;
- if (!(card = snd_card_new(index, id, THIS_MODULE,
- sizeof(struct snd_miro))))
- return -ENOMEM;
+ error = snd_card_create(index, id, THIS_MODULE,
+ sizeof(struct snd_miro), &card);
+ if (error < 0)
+ return error;
card->private_free = snd_card_miro_free;
miro = card->private_data;
diff --git a/sound/isa/opti9xx/opti92x-ad1848.c b/sound/isa/opti9xx/opti92x-ad1848.c
index 19706b0d849..5cd555325b9 100644
--- a/sound/isa/opti9xx/opti92x-ad1848.c
+++ b/sound/isa/opti9xx/opti92x-ad1848.c
@@ -252,7 +252,7 @@ static int __devinit snd_opti9xx_init(struct snd_opti9xx *chip,
#endif /* OPTi93X */
default:
- snd_printk("chip %d not supported\n", hardware);
+ snd_printk(KERN_ERR "chip %d not supported\n", hardware);
return -ENODEV;
}
return 0;
@@ -294,7 +294,7 @@ static unsigned char snd_opti9xx_read(struct snd_opti9xx *chip,
#endif /* OPTi93X */
default:
- snd_printk("chip %d not supported\n", chip->hardware);
+ snd_printk(KERN_ERR "chip %d not supported\n", chip->hardware);
}
spin_unlock_irqrestore(&chip->lock, flags);
@@ -336,7 +336,7 @@ static void snd_opti9xx_write(struct snd_opti9xx *chip, unsigned char reg,
#endif /* OPTi93X */
default:
- snd_printk("chip %d not supported\n", chip->hardware);
+ snd_printk(KERN_ERR "chip %d not supported\n", chip->hardware);
}
spin_unlock_irqrestore(&chip->lock, flags);
@@ -412,7 +412,7 @@ static int __devinit snd_opti9xx_configure(struct snd_opti9xx *chip)
#endif /* OPTi93X */
default:
- snd_printk("chip %d not supported\n", chip->hardware);
+ snd_printk(KERN_ERR "chip %d not supported\n", chip->hardware);
return -EINVAL;
}
@@ -430,7 +430,8 @@ static int __devinit snd_opti9xx_configure(struct snd_opti9xx *chip)
wss_base_bits = 0x02;
break;
default:
- snd_printk("WSS port 0x%lx not valid\n", chip->wss_base);
+ snd_printk(KERN_WARNING "WSS port 0x%lx not valid\n",
+ chip->wss_base);
goto __skip_base;
}
snd_opti9xx_write_mask(chip, OPTi9XX_MC_REG(1), wss_base_bits << 4, 0x30);
@@ -455,7 +456,7 @@ __skip_base:
irq_bits = 0x04;
break;
default:
- snd_printk("WSS irq # %d not valid\n", chip->irq);
+ snd_printk(KERN_WARNING "WSS irq # %d not valid\n", chip->irq);
goto __skip_resources;
}
@@ -470,13 +471,14 @@ __skip_base:
dma_bits = 0x03;
break;
default:
- snd_printk("WSS dma1 # %d not valid\n", chip->dma1);
+ snd_printk(KERN_WARNING "WSS dma1 # %d not valid\n",
+ chip->dma1);
goto __skip_resources;
}
#if defined(CS4231) || defined(OPTi93X)
if (chip->dma1 == chip->dma2) {
- snd_printk("don't want to share dmas\n");
+ snd_printk(KERN_ERR "don't want to share dmas\n");
return -EBUSY;
}
@@ -485,7 +487,8 @@ __skip_base:
case 1:
break;
default:
- snd_printk("WSS dma2 # %d not valid\n", chip->dma2);
+ snd_printk(KERN_WARNING "WSS dma2 # %d not valid\n",
+ chip->dma2);
goto __skip_resources;
}
dma_bits |= 0x04;
@@ -516,7 +519,8 @@ __skip_resources:
mpu_port_bits = 0x00;
break;
default:
- snd_printk("MPU-401 port 0x%lx not valid\n",
+ snd_printk(KERN_WARNING
+ "MPU-401 port 0x%lx not valid\n",
chip->mpu_port);
goto __skip_mpu;
}
@@ -535,7 +539,7 @@ __skip_resources:
mpu_irq_bits = 0x01;
break;
default:
- snd_printk("MPU-401 irq # %d not valid\n",
+ snd_printk(KERN_WARNING "MPU-401 irq # %d not valid\n",
chip->mpu_irq);
goto __skip_mpu;
}
@@ -726,7 +730,7 @@ static int __devinit snd_opti9xx_probe(struct snd_card *card)
if (chip->wss_base == SNDRV_AUTO_PORT) {
chip->wss_base = snd_legacy_find_free_ioport(possible_ports, 4);
if (chip->wss_base < 0) {
- snd_printk("unable to find a free WSS port\n");
+ snd_printk(KERN_ERR "unable to find a free WSS port\n");
return -EBUSY;
}
}
@@ -815,14 +819,8 @@ static int __devinit snd_opti9xx_probe(struct snd_card *card)
chip->fm_port, chip->fm_port + 4 - 1);
}
if (opl3) {
-#ifdef CS4231
- const int t1dev = 1;
-#else
- const int t1dev = 0;
-#endif
- if ((error = snd_opl3_timer_new(opl3, t1dev, t1dev+1)) < 0)
- return error;
- if ((error = snd_opl3_hwdep_new(opl3, 0, 1, &synth)) < 0)
+ error = snd_opl3_hwdep_new(opl3, 0, 1, &synth);
+ if (error < 0)
return error;
}
}
@@ -830,15 +828,18 @@ static int __devinit snd_opti9xx_probe(struct snd_card *card)
return snd_card_register(card);
}
-static struct snd_card *snd_opti9xx_card_new(void)
+static int snd_opti9xx_card_new(struct snd_card **cardp)
{
struct snd_card *card;
+ int err;
- card = snd_card_new(index, id, THIS_MODULE, sizeof(struct snd_opti9xx));
- if (! card)
- return NULL;
+ err = snd_card_create(index, id, THIS_MODULE,
+ sizeof(struct snd_opti9xx), &card);
+ if (err < 0)
+ return err;
card->private_free = snd_card_opti9xx_free;
- return card;
+ *cardp = card;
+ return 0;
}
static int __devinit snd_opti9xx_isa_match(struct device *devptr,
@@ -897,15 +898,15 @@ static int __devinit snd_opti9xx_isa_probe(struct device *devptr,
#if defined(CS4231) || defined(OPTi93X)
if (dma2 == SNDRV_AUTO_DMA) {
if ((dma2 = snd_legacy_find_free_dma(possible_dma2s[dma1 % 4])) < 0) {
- snd_printk("unable to find a free DMA2\n");
+ snd_printk(KERN_ERR "unable to find a free DMA2\n");
return -EBUSY;
}
}
#endif
- card = snd_opti9xx_card_new();
- if (! card)
- return -ENOMEM;
+ error = snd_opti9xx_card_new(&card);
+ if (error < 0)
+ return error;
if ((error = snd_card_opti9xx_detect(card, card->private_data)) < 0) {
snd_card_free(card);
@@ -950,9 +951,9 @@ static int __devinit snd_opti9xx_pnp_probe(struct pnp_card_link *pcard,
return -EBUSY;
if (! isapnp)
return -ENODEV;
- card = snd_opti9xx_card_new();
- if (! card)
- return -ENOMEM;
+ error = snd_opti9xx_card_new(&card);
+ if (error < 0)
+ return error;
chip = card->private_data;
hw = snd_card_opti9xx_pnp(chip, pcard, pid);
diff --git a/sound/isa/sb/es968.c b/sound/isa/sb/es968.c
index c8c8e214c84..cafc3a7316a 100644
--- a/sound/isa/sb/es968.c
+++ b/sound/isa/sb/es968.c
@@ -108,9 +108,10 @@ static int __devinit snd_card_es968_probe(int dev,
struct snd_card *card;
struct snd_card_es968 *acard;
- if ((card = snd_card_new(index[dev], id[dev], THIS_MODULE,
- sizeof(struct snd_card_es968))) == NULL)
- return -ENOMEM;
+ error = snd_card_create(index[dev], id[dev], THIS_MODULE,
+ sizeof(struct snd_card_es968), &card);
+ if (error < 0)
+ return error;
acard = card->private_data;
if ((error = snd_card_es968_pnp(dev, acard, pcard, pid))) {
snd_card_free(card);
diff --git a/sound/isa/sb/sb16.c b/sound/isa/sb/sb16.c
index 2c201f78ce5..519c36346de 100644
--- a/sound/isa/sb/sb16.c
+++ b/sound/isa/sb/sb16.c
@@ -324,14 +324,18 @@ static void snd_sb16_free(struct snd_card *card)
#define is_isapnp_selected(dev) 0
#endif
-static struct snd_card *snd_sb16_card_new(int dev)
+static int snd_sb16_card_new(int dev, struct snd_card **cardp)
{
- struct snd_card *card = snd_card_new(index[dev], id[dev], THIS_MODULE,
- sizeof(struct snd_card_sb16));
- if (card == NULL)
- return NULL;
+ struct snd_card *card;
+ int err;
+
+ err = snd_card_create(index[dev], id[dev], THIS_MODULE,
+ sizeof(struct snd_card_sb16), &card);
+ if (err < 0)
+ return err;
card->private_free = snd_sb16_free;
- return card;
+ *cardp = card;
+ return 0;
}
static int __devinit snd_sb16_probe(struct snd_card *card, int dev)
@@ -489,9 +493,9 @@ static int __devinit snd_sb16_isa_probe1(int dev, struct device *pdev)
struct snd_card *card;
int err;
- card = snd_sb16_card_new(dev);
- if (! card)
- return -ENOMEM;
+ err = snd_sb16_card_new(dev, &card);
+ if (err < 0)
+ return err;
acard = card->private_data;
/* non-PnP FM port address is hardwired with base port address */
@@ -610,9 +614,9 @@ static int __devinit snd_sb16_pnp_detect(struct pnp_card_link *pcard,
for ( ; dev < SNDRV_CARDS; dev++) {
if (!enable[dev] || !isapnp[dev])
continue;
- card = snd_sb16_card_new(dev);
- if (! card)
- return -ENOMEM;
+ res = snd_sb16_card_new(dev, &card);
+ if (res < 0)
+ return res;
snd_card_set_dev(card, &pcard->card->dev);
if ((res = snd_card_sb16_pnp(dev, card->private_data, pcard, pid)) < 0 ||
(res = snd_sb16_probe(card, dev)) < 0) {
diff --git a/sound/isa/sb/sb8.c b/sound/isa/sb/sb8.c
index ea06877be4b..3cd57ee5466 100644
--- a/sound/isa/sb/sb8.c
+++ b/sound/isa/sb/sb8.c
@@ -103,10 +103,10 @@ static int __devinit snd_sb8_probe(struct device *pdev, unsigned int dev)
struct snd_opl3 *opl3;
int err;
- card = snd_card_new(index[dev], id[dev], THIS_MODULE,
- sizeof(struct snd_sb8));
- if (card == NULL)
- return -ENOMEM;
+ err = snd_card_create(index[dev], id[dev], THIS_MODULE,
+ sizeof(struct snd_sb8), &card);
+ if (err < 0)
+ return err;
acard = card->private_data;
card->private_free = snd_sb8_free;
diff --git a/sound/isa/sb/sb_mixer.c b/sound/isa/sb/sb_mixer.c
index 406a431af91..475220bbcc9 100644
--- a/sound/isa/sb/sb_mixer.c
+++ b/sound/isa/sb/sb_mixer.c
@@ -182,7 +182,7 @@ static int snd_sbmixer_put_double(struct snd_kcontrol *kcontrol, struct snd_ctl_
static int snd_dt019x_input_sw_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
{
- static char *texts[5] = {
+ static const char *texts[5] = {
"CD", "Mic", "Line", "Synth", "Master"
};
@@ -269,12 +269,73 @@ static int snd_dt019x_input_sw_put(struct snd_kcontrol *kcontrol, struct snd_ctl
}
/*
+ * ALS4000 mono recording control switch
+ */
+
+static int snd_als4k_mono_capture_route_info(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_info *uinfo)
+{
+ static const char *texts[3] = {
+ "L chan only", "R chan only", "L ch/2 + R ch/2"
+ };
+
+ uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
+ uinfo->count = 1;
+ uinfo->value.enumerated.items = 3;
+ if (uinfo->value.enumerated.item > 2)
+ uinfo->value.enumerated.item = 2;
+ strcpy(uinfo->value.enumerated.name,
+ texts[uinfo->value.enumerated.item]);
+ return 0;
+}
+
+static int snd_als4k_mono_capture_route_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_sb *sb = snd_kcontrol_chip(kcontrol);
+ unsigned long flags;
+ unsigned char oval;
+
+ spin_lock_irqsave(&sb->mixer_lock, flags);
+ oval = snd_sbmixer_read(sb, SB_ALS4000_MONO_IO_CTRL);
+ spin_unlock_irqrestore(&sb->mixer_lock, flags);
+ oval >>= 6;
+ if (oval > 2)
+ oval = 2;
+
+ ucontrol->value.enumerated.item[0] = oval;
+ return 0;
+}
+
+static int snd_als4k_mono_capture_route_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_sb *sb = snd_kcontrol_chip(kcontrol);
+ unsigned long flags;
+ int change;
+ unsigned char nval, oval;
+
+ if (ucontrol->value.enumerated.item[0] > 2)
+ return -EINVAL;
+ spin_lock_irqsave(&sb->mixer_lock, flags);
+ oval = snd_sbmixer_read(sb, SB_ALS4000_MONO_IO_CTRL);
+
+ nval = (oval & ~(3 << 6))
+ | (ucontrol->value.enumerated.item[0] << 6);
+ change = nval != oval;
+ if (change)
+ snd_sbmixer_write(sb, SB_ALS4000_MONO_IO_CTRL, nval);
+ spin_unlock_irqrestore(&sb->mixer_lock, flags);
+ return change;
+}
+
+/*
* SBPRO input multiplexer
*/
static int snd_sb8mixer_info_mux(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
{
- static char *texts[3] = {
+ static const char *texts[3] = {
"Mic", "CD", "Line"
};
@@ -442,6 +503,12 @@ int snd_sbmixer_add_ctl(struct snd_sb *chip, const char *name, int index, int ty
.get = snd_dt019x_input_sw_get,
.put = snd_dt019x_input_sw_put,
},
+ [SB_MIX_MONO_CAPTURE_ALS4K] = {
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+ .info = snd_als4k_mono_capture_route_info,
+ .get = snd_als4k_mono_capture_route_get,
+ .put = snd_als4k_mono_capture_route_put,
+ },
};
struct snd_kcontrol *ctl;
int err;
@@ -636,6 +703,8 @@ static struct sbmix_elem snd_dt019x_ctl_capture_source =
};
static struct sbmix_elem *snd_dt019x_controls[] = {
+ /* ALS4000 below has some parts which we might be lacking,
+ * e.g. snd_als4000_ctl_mono_playback_switch - check it! */
&snd_dt019x_ctl_master_play_vol,
&snd_dt019x_ctl_pcm_play_vol,
&snd_dt019x_ctl_synth_play_vol,
@@ -666,18 +735,21 @@ static unsigned char snd_dt019x_init_values[][2] = {
/*
* ALS4000 specific mixer elements
*/
-/* FIXME: SB_ALS4000_MONO_IO_CTRL needs output select ctrl! */
static struct sbmix_elem snd_als4000_ctl_master_mono_playback_switch =
SB_SINGLE("Master Mono Playback Switch", SB_ALS4000_MONO_IO_CTRL, 5, 1);
-static struct sbmix_elem snd_als4000_ctl_master_mono_capture_route =
- SB_SINGLE("Master Mono Capture Route", SB_ALS4000_MONO_IO_CTRL, 6, 0x03);
-/* FIXME: mono playback switch also available on DT019X? */
+static struct sbmix_elem snd_als4k_ctl_master_mono_capture_route = {
+ .name = "Master Mono Capture Route",
+ .type = SB_MIX_MONO_CAPTURE_ALS4K
+ };
static struct sbmix_elem snd_als4000_ctl_mono_playback_switch =
SB_SINGLE("Mono Playback Switch", SB_DT019X_OUTPUT_SW2, 0, 1);
static struct sbmix_elem snd_als4000_ctl_mic_20db_boost =
SB_SINGLE("Mic Boost (+20dB)", SB_ALS4000_MIC_IN_GAIN, 0, 0x03);
-static struct sbmix_elem snd_als4000_ctl_mixer_loopback =
- SB_SINGLE("Analog Loopback", SB_ALS4000_MIC_IN_GAIN, 7, 0x01);
+static struct sbmix_elem snd_als4000_ctl_mixer_analog_loopback =
+ SB_SINGLE("Analog Loopback Switch", SB_ALS4000_MIC_IN_GAIN, 7, 0x01);
+static struct sbmix_elem snd_als4000_ctl_mixer_digital_loopback =
+ SB_SINGLE("Digital Loopback Switch",
+ SB_ALS4000_CR3_CONFIGURATION, 7, 0x01);
/* FIXME: functionality of 3D controls might be swapped, I didn't find
* a description of how to identify what is supposed to be what */
static struct sbmix_elem snd_als4000_3d_control_switch =
@@ -694,6 +766,9 @@ static struct sbmix_elem snd_als4000_3d_control_delay =
SB_SINGLE("3D Control - Wide", SB_ALS4000_3D_TIME_DELAY, 0, 0x0f);
static struct sbmix_elem snd_als4000_3d_control_poweroff_switch =
SB_SINGLE("3D PowerOff Switch", SB_ALS4000_3D_TIME_DELAY, 4, 0x01);
+static struct sbmix_elem snd_als4000_ctl_3db_freq_control_switch =
+ SB_SINGLE("Master Playback 8kHz / 20kHz LPF Switch",
+ SB_ALS4000_FMDAC, 5, 0x01);
#ifdef NOT_AVAILABLE
static struct sbmix_elem snd_als4000_ctl_fmdac =
SB_SINGLE("FMDAC Switch (Option ?)", SB_ALS4000_FMDAC, 0, 0x01);
@@ -702,35 +777,37 @@ static struct sbmix_elem snd_als4000_ctl_qsound =
#endif
static struct sbmix_elem *snd_als4000_controls[] = {
- &snd_sb16_ctl_master_play_vol,
- &snd_dt019x_ctl_pcm_play_switch,
- &snd_sb16_ctl_pcm_play_vol,
- &snd_sb16_ctl_synth_capture_route,
- &snd_dt019x_ctl_synth_play_switch,
- &snd_sb16_ctl_synth_play_vol,
- &snd_sb16_ctl_cd_capture_route,
- &snd_sb16_ctl_cd_play_switch,
- &snd_sb16_ctl_cd_play_vol,
- &snd_sb16_ctl_line_capture_route,
- &snd_sb16_ctl_line_play_switch,
- &snd_sb16_ctl_line_play_vol,
- &snd_sb16_ctl_mic_capture_route,
- &snd_als4000_ctl_mic_20db_boost,
- &snd_sb16_ctl_auto_mic_gain,
- &snd_sb16_ctl_mic_play_switch,
- &snd_sb16_ctl_mic_play_vol,
- &snd_sb16_ctl_pc_speaker_vol,
- &snd_sb16_ctl_capture_vol,
- &snd_sb16_ctl_play_vol,
- &snd_als4000_ctl_master_mono_playback_switch,
- &snd_als4000_ctl_master_mono_capture_route,
- &snd_als4000_ctl_mono_playback_switch,
- &snd_als4000_ctl_mixer_loopback,
- &snd_als4000_3d_control_switch,
- &snd_als4000_3d_control_ratio,
- &snd_als4000_3d_control_freq,
- &snd_als4000_3d_control_delay,
- &snd_als4000_3d_control_poweroff_switch,
+ /* ALS4000a.PDF regs page */
+ &snd_sb16_ctl_master_play_vol, /* MX30/31 12 */
+ &snd_dt019x_ctl_pcm_play_switch, /* MX4C 16 */
+ &snd_sb16_ctl_pcm_play_vol, /* MX32/33 12 */
+ &snd_sb16_ctl_synth_capture_route, /* MX3D/3E 14 */
+ &snd_dt019x_ctl_synth_play_switch, /* MX4C 16 */
+ &snd_sb16_ctl_synth_play_vol, /* MX34/35 12/13 */
+ &snd_sb16_ctl_cd_capture_route, /* MX3D/3E 14 */
+ &snd_sb16_ctl_cd_play_switch, /* MX3C 14 */
+ &snd_sb16_ctl_cd_play_vol, /* MX36/37 13 */
+ &snd_sb16_ctl_line_capture_route, /* MX3D/3E 14 */
+ &snd_sb16_ctl_line_play_switch, /* MX3C 14 */
+ &snd_sb16_ctl_line_play_vol, /* MX38/39 13 */
+ &snd_sb16_ctl_mic_capture_route, /* MX3D/3E 14 */
+ &snd_als4000_ctl_mic_20db_boost, /* MX4D 16 */
+ &snd_sb16_ctl_mic_play_switch, /* MX3C 14 */
+ &snd_sb16_ctl_mic_play_vol, /* MX3A 13 */
+ &snd_sb16_ctl_pc_speaker_vol, /* MX3B 14 */
+ &snd_sb16_ctl_capture_vol, /* MX3F/40 15 */
+ &snd_sb16_ctl_play_vol, /* MX41/42 15 */
+ &snd_als4000_ctl_master_mono_playback_switch, /* MX4C 16 */
+ &snd_als4k_ctl_master_mono_capture_route, /* MX4B 16 */
+ &snd_als4000_ctl_mono_playback_switch, /* MX4C 16 */
+ &snd_als4000_ctl_mixer_analog_loopback, /* MX4D 16 */
+ &snd_als4000_ctl_mixer_digital_loopback, /* CR3 21 */
+ &snd_als4000_3d_control_switch, /* MX50 17 */
+ &snd_als4000_3d_control_ratio, /* MX50 17 */
+ &snd_als4000_3d_control_freq, /* MX50 17 */
+ &snd_als4000_3d_control_delay, /* MX51 18 */
+ &snd_als4000_3d_control_poweroff_switch, /* MX51 18 */
+ &snd_als4000_ctl_3db_freq_control_switch, /* MX4F 17 */
#ifdef NOT_AVAILABLE
&snd_als4000_ctl_fmdac,
&snd_als4000_ctl_qsound,
@@ -905,13 +982,14 @@ static unsigned char dt019x_saved_regs[] = {
};
static unsigned char als4000_saved_regs[] = {
+ /* please verify in dsheet whether regs to be added
+ are actually real H/W or just dummy */
SB_DSP4_MASTER_DEV, SB_DSP4_MASTER_DEV + 1,
SB_DSP4_OUTPUT_SW,
SB_DSP4_PCM_DEV, SB_DSP4_PCM_DEV + 1,
SB_DSP4_INPUT_LEFT, SB_DSP4_INPUT_RIGHT,
SB_DSP4_SYNTH_DEV, SB_DSP4_SYNTH_DEV + 1,
SB_DSP4_CD_DEV, SB_DSP4_CD_DEV + 1,
- SB_DSP4_MIC_AGC,
SB_DSP4_MIC_DEV,
SB_DSP4_SPEAKER_DEV,
SB_DSP4_IGAIN_DEV, SB_DSP4_IGAIN_DEV + 1,
@@ -919,8 +997,10 @@ static unsigned char als4000_saved_regs[] = {
SB_DT019X_OUTPUT_SW2,
SB_ALS4000_MONO_IO_CTRL,
SB_ALS4000_MIC_IN_GAIN,
+ SB_ALS4000_FMDAC,
SB_ALS4000_3D_SND_FX,
SB_ALS4000_3D_TIME_DELAY,
+ SB_ALS4000_CR3_CONFIGURATION,
};
static void save_mixer(struct snd_sb *chip, unsigned char *regs, int num_regs)
diff --git a/sound/isa/sc6000.c b/sound/isa/sc6000.c
index ca35924dc3b..782010608ef 100644
--- a/sound/isa/sc6000.c
+++ b/sound/isa/sc6000.c
@@ -489,9 +489,9 @@ static int __devinit snd_sc6000_probe(struct device *devptr, unsigned int dev)
char __iomem *vmss_port;
- card = snd_card_new(index[dev], id[dev], THIS_MODULE, 0);
- if (!card)
- return -ENOMEM;
+ err = snd_card_create(index[dev], id[dev], THIS_MODULE, 0, &card);
+ if (err < 0)
+ return err;
if (xirq == SNDRV_AUTO_IRQ) {
xirq = snd_legacy_find_free_irq(possible_irqs);
@@ -576,10 +576,6 @@ static int __devinit snd_sc6000_probe(struct device *devptr, unsigned int dev)
snd_printk(KERN_ERR PFX "no OPL device at 0x%x-0x%x ?\n",
0x388, 0x388 + 2);
} else {
- err = snd_opl3_timer_new(opl3, 0, 1);
- if (err < 0)
- goto err_unmap2;
-
err = snd_opl3_hwdep_new(opl3, 0, 1, NULL);
if (err < 0)
goto err_unmap2;
diff --git a/sound/isa/sgalaxy.c b/sound/isa/sgalaxy.c
index 2c7503bf127..6fe27b9d944 100644
--- a/sound/isa/sgalaxy.c
+++ b/sound/isa/sgalaxy.c
@@ -243,9 +243,9 @@ static int __devinit snd_sgalaxy_probe(struct device *devptr, unsigned int dev)
struct snd_card *card;
struct snd_wss *chip;
- card = snd_card_new(index[dev], id[dev], THIS_MODULE, 0);
- if (card == NULL)
- return -ENOMEM;
+ err = snd_card_create(index[dev], id[dev], THIS_MODULE, 0, &card);
+ if (err < 0)
+ return err;
xirq = irq[dev];
if (xirq == SNDRV_AUTO_IRQ) {
diff --git a/sound/isa/sscape.c b/sound/isa/sscape.c
index 48a16d86583..66187122377 100644
--- a/sound/isa/sscape.c
+++ b/sound/isa/sscape.c
@@ -89,9 +89,6 @@ MODULE_DEVICE_TABLE(pnp_card, sscape_pnpids);
#endif
-#define MPU401_IO(i) ((i) + 0)
-#define MIDI_DATA_IO(i) ((i) + 0)
-#define MIDI_CTRL_IO(i) ((i) + 1)
#define HOST_CTRL_IO(i) ((i) + 2)
#define HOST_DATA_IO(i) ((i) + 3)
#define ODIE_ADDR_IO(i) ((i) + 4)
@@ -129,9 +126,6 @@ enum GA_REG {
#define DMA_8BIT 0x80
-#define AD1845_FREQ_SEL_MSB 0x16
-#define AD1845_FREQ_SEL_LSB 0x17
-
enum card_type {
SSCAPE,
SSCAPE_PNP,
@@ -141,8 +135,6 @@ enum card_type {
struct soundscape {
spinlock_t lock;
unsigned io_base;
- unsigned wss_base;
- int codec_type;
int ic_type;
enum card_type type;
struct resource *io_res;
@@ -330,7 +322,7 @@ static int host_write_ctrl_unsafe(unsigned io_base, unsigned char data,
*/
static inline int verify_mpu401(const struct snd_mpu401 * mpu)
{
- return ((inb(MIDI_CTRL_IO(mpu->port)) & 0xc0) == 0x80);
+ return ((inb(MPU401C(mpu)) & 0xc0) == 0x80);
}
/*
@@ -338,7 +330,7 @@ static inline int verify_mpu401(const struct snd_mpu401 * mpu)
*/
static inline void initialise_mpu401(const struct snd_mpu401 * mpu)
{
- outb(0, MIDI_DATA_IO(mpu->port));
+ outb(0, MPU401D(mpu));
}
/*
@@ -396,20 +388,20 @@ static int sscape_wait_dma_unsafe(unsigned io_base, enum GA_REG reg, unsigned ti
*/
static int obp_startup_ack(struct soundscape *s, unsigned timeout)
{
- while (timeout != 0) {
+ unsigned long end_time = jiffies + msecs_to_jiffies(timeout);
+
+ do {
unsigned long flags;
unsigned char x;
- schedule_timeout_uninterruptible(1);
-
spin_lock_irqsave(&s->lock, flags);
x = inb(HOST_DATA_IO(s->io_base));
spin_unlock_irqrestore(&s->lock, flags);
if ((x & 0xfe) == 0xfe)
return 1;
- --timeout;
- } /* while */
+ msleep(10);
+ } while (time_before(jiffies, end_time));
return 0;
}
@@ -423,20 +415,20 @@ static int obp_startup_ack(struct soundscape *s, unsigned timeout)
*/
static int host_startup_ack(struct soundscape *s, unsigned timeout)
{
- while (timeout != 0) {
+ unsigned long end_time = jiffies + msecs_to_jiffies(timeout);
+
+ do {
unsigned long flags;
unsigned char x;
- schedule_timeout_uninterruptible(1);
-
spin_lock_irqsave(&s->lock, flags);
x = inb(HOST_DATA_IO(s->io_base));
spin_unlock_irqrestore(&s->lock, flags);
if (x == 0xfe)
return 1;
- --timeout;
- } /* while */
+ msleep(10);
+ } while (time_before(jiffies, end_time));
return 0;
}
@@ -532,10 +524,10 @@ static int upload_dma_data(struct soundscape *s,
* give it 5 seconds (max) ...
*/
ret = 0;
- if (!obp_startup_ack(s, 5)) {
+ if (!obp_startup_ack(s, 5000)) {
snd_printk(KERN_ERR "sscape: No response from on-board processor after upload\n");
ret = -EAGAIN;
- } else if (!host_startup_ack(s, 5)) {
+ } else if (!host_startup_ack(s, 5000)) {
snd_printk(KERN_ERR "sscape: SoundScape failed to initialise\n");
ret = -EAGAIN;
}
@@ -732,13 +724,7 @@ static int sscape_midi_get(struct snd_kcontrol *kctl,
unsigned long flags;
spin_lock_irqsave(&s->lock, flags);
- set_host_mode_unsafe(s->io_base);
-
- if (host_write_ctrl_unsafe(s->io_base, CMD_GET_MIDI_VOL, 100)) {
- uctl->value.integer.value[0] = host_read_ctrl_unsafe(s->io_base, 100);
- }
-
- set_midi_mode_unsafe(s->io_base);
+ uctl->value.integer.value[0] = s->midi_vol;
spin_unlock_irqrestore(&s->lock, flags);
return 0;
}
@@ -773,6 +759,7 @@ static int sscape_midi_put(struct snd_kcontrol *kctl,
change = (host_write_ctrl_unsafe(s->io_base, CMD_SET_MIDI_VOL, 100)
&& host_write_ctrl_unsafe(s->io_base, ((unsigned char) uctl->value.integer. value[0]) & 127, 100)
&& host_write_ctrl_unsafe(s->io_base, CMD_XXX_MIDI_VOL, 100));
+ s->midi_vol = (unsigned char) uctl->value.integer.value[0] & 127;
__skip_change:
/*
@@ -815,12 +802,11 @@ static unsigned __devinit get_irq_config(int irq)
* Perform certain arcane port-checks to see whether there
* is a SoundScape board lurking behind the given ports.
*/
-static int __devinit detect_sscape(struct soundscape *s)
+static int __devinit detect_sscape(struct soundscape *s, long wss_io)
{
unsigned long flags;
unsigned d;
int retval = 0;
- int codec = s->wss_base;
spin_lock_irqsave(&s->lock, flags);
@@ -836,13 +822,11 @@ static int __devinit detect_sscape(struct soundscape *s)
if ((d & 0x80) != 0)
goto _done;
- if (d == 0) {
- s->codec_type = 1;
+ if (d == 0)
s->ic_type = IC_ODIE;
- } else if ((d & 0x60) != 0) {
- s->codec_type = 2;
+ else if ((d & 0x60) != 0)
s->ic_type = IC_OPUS;
- } else
+ else
goto _done;
outb(0xfa, ODIE_ADDR_IO(s->io_base));
@@ -862,10 +846,10 @@ static int __devinit detect_sscape(struct soundscape *s)
sscape_write_unsafe(s->io_base, GA_HMCTL_REG, d | 0xc0);
if (s->type == SSCAPE_VIVO)
- codec += 4;
+ wss_io += 4;
/* wait for WSS codec */
for (d = 0; d < 500; d++) {
- if ((inb(codec) & 0x80) == 0)
+ if ((inb(wss_io) & 0x80) == 0)
break;
spin_unlock_irqrestore(&s->lock, flags);
msleep(1);
@@ -955,82 +939,6 @@ static int __devinit create_mpu401(struct snd_card *card, int devnum, unsigned l
/*
- * Override for the CS4231 playback format function.
- * The AD1845 has much simpler format and rate selection.
- */
-static void ad1845_playback_format(struct snd_wss *chip,
- struct snd_pcm_hw_params *params,
- unsigned char format)
-{
- unsigned long flags;
- unsigned rate = params_rate(params);
-
- /*
- * The AD1845 can't handle sample frequencies
- * outside of 4 kHZ to 50 kHZ
- */
- if (rate > 50000)
- rate = 50000;
- else if (rate < 4000)
- rate = 4000;
-
- spin_lock_irqsave(&chip->reg_lock, flags);
-
- /*
- * Program the AD1845 correctly for the playback stream.
- * Note that we do NOT need to toggle the MCE bit because
- * the PLAYBACK_ENABLE bit of the Interface Configuration
- * register is set.
- *
- * NOTE: We seem to need to write to the MSB before the LSB
- * to get the correct sample frequency.
- */
- snd_wss_out(chip, CS4231_PLAYBK_FORMAT, (format & 0xf0));
- snd_wss_out(chip, AD1845_FREQ_SEL_MSB, (unsigned char) (rate >> 8));
- snd_wss_out(chip, AD1845_FREQ_SEL_LSB, (unsigned char) rate);
-
- spin_unlock_irqrestore(&chip->reg_lock, flags);
-}
-
-/*
- * Override for the CS4231 capture format function.
- * The AD1845 has much simpler format and rate selection.
- */
-static void ad1845_capture_format(struct snd_wss *chip,
- struct snd_pcm_hw_params *params,
- unsigned char format)
-{
- unsigned long flags;
- unsigned rate = params_rate(params);
-
- /*
- * The AD1845 can't handle sample frequencies
- * outside of 4 kHZ to 50 kHZ
- */
- if (rate > 50000)
- rate = 50000;
- else if (rate < 4000)
- rate = 4000;
-
- spin_lock_irqsave(&chip->reg_lock, flags);
-
- /*
- * Program the AD1845 correctly for the playback stream.
- * Note that we do NOT need to toggle the MCE bit because
- * the CAPTURE_ENABLE bit of the Interface Configuration
- * register is set.
- *
- * NOTE: We seem to need to write to the MSB before the LSB
- * to get the correct sample frequency.
- */
- snd_wss_out(chip, CS4231_REC_FORMAT, (format & 0xf0));
- snd_wss_out(chip, AD1845_FREQ_SEL_MSB, (unsigned char) (rate >> 8));
- snd_wss_out(chip, AD1845_FREQ_SEL_LSB, (unsigned char) rate);
-
- spin_unlock_irqrestore(&chip->reg_lock, flags);
-}
-
-/*
* Create an AD1845 PCM subdevice on the SoundScape. The AD1845
* is very much like a CS4231, with a few extra bits. We will
* try to support at least some of the extra bits by overriding
@@ -1055,11 +963,6 @@ static int __devinit create_ad1845(struct snd_card *card, unsigned port,
unsigned long flags;
struct snd_pcm *pcm;
-#define AD1845_FREQ_SEL_ENABLE 0x08
-
-#define AD1845_PWR_DOWN_CTRL 0x1b
-#define AD1845_CRYS_CLOCK_SEL 0x1d
-
/*
* It turns out that the PLAYBACK_ENABLE bit is set
* by the lowlevel driver ...
@@ -1074,7 +977,6 @@ static int __devinit create_ad1845(struct snd_card *card, unsigned port,
*/
if (sscape->type != SSCAPE_VIVO) {
- int val;
/*
* The input clock frequency on the SoundScape must
* be 14.31818 MHz, because we must set this register
@@ -1082,22 +984,10 @@ static int __devinit create_ad1845(struct snd_card *card, unsigned port,
*/
snd_wss_mce_up(chip);
spin_lock_irqsave(&chip->reg_lock, flags);
- snd_wss_out(chip, AD1845_CRYS_CLOCK_SEL, 0x20);
+ snd_wss_out(chip, AD1845_CLOCK, 0x20);
spin_unlock_irqrestore(&chip->reg_lock, flags);
snd_wss_mce_down(chip);
- /*
- * More custom configuration:
- * a) select "mode 2" and provide a current drive of 8mA
- * b) enable frequency selection (for capture/playback)
- */
- spin_lock_irqsave(&chip->reg_lock, flags);
- snd_wss_out(chip, CS4231_MISC_INFO,
- CS4231_MODE2 | 0x10);
- val = snd_wss_in(chip, AD1845_PWR_DOWN_CTRL);
- snd_wss_out(chip, AD1845_PWR_DOWN_CTRL,
- val | AD1845_FREQ_SEL_ENABLE);
- spin_unlock_irqrestore(&chip->reg_lock, flags);
}
err = snd_wss_pcm(chip, 0, &pcm);
@@ -1113,11 +1003,13 @@ static int __devinit create_ad1845(struct snd_card *card, unsigned port,
"for AD1845 chip\n");
goto _error;
}
- err = snd_wss_timer(chip, 0, NULL);
- if (err < 0) {
- snd_printk(KERN_ERR "sscape: No timer device "
- "for AD1845 chip\n");
- goto _error;
+ if (chip->hardware != WSS_HW_AD1848) {
+ err = snd_wss_timer(chip, 0, NULL);
+ if (err < 0) {
+ snd_printk(KERN_ERR "sscape: No timer device "
+ "for AD1845 chip\n");
+ goto _error;
+ }
}
if (sscape->type != SSCAPE_VIVO) {
@@ -1128,8 +1020,6 @@ static int __devinit create_ad1845(struct snd_card *card, unsigned port,
"MIDI mixer control\n");
goto _error;
}
- chip->set_playback_format = ad1845_playback_format;
- chip->set_capture_format = ad1845_capture_format;
}
strcpy(card->driver, "SoundScape");
@@ -1157,7 +1047,6 @@ static int __devinit create_sscape(int dev, struct snd_card *card)
unsigned dma_cfg;
unsigned irq_cfg;
unsigned mpu_irq_cfg;
- unsigned xport;
struct resource *io_res;
struct resource *wss_res;
unsigned long flags;
@@ -1177,15 +1066,15 @@ static int __devinit create_sscape(int dev, struct snd_card *card)
printk(KERN_ERR "sscape: Invalid IRQ %d\n", mpu_irq[dev]);
return -ENXIO;
}
- xport = port[dev];
/*
* Grab IO ports that we will need to probe so that we
* can detect and control this hardware ...
*/
- io_res = request_region(xport, 8, "SoundScape");
+ io_res = request_region(port[dev], 8, "SoundScape");
if (!io_res) {
- snd_printk(KERN_ERR "sscape: can't grab port 0x%x\n", xport);
+ snd_printk(KERN_ERR
+ "sscape: can't grab port 0x%lx\n", port[dev]);
return -EBUSY;
}
wss_res = NULL;
@@ -1212,10 +1101,9 @@ static int __devinit create_sscape(int dev, struct snd_card *card)
spin_lock_init(&sscape->fwlock);
sscape->io_res = io_res;
sscape->wss_res = wss_res;
- sscape->io_base = xport;
- sscape->wss_base = wss_port[dev];
+ sscape->io_base = port[dev];
- if (!detect_sscape(sscape)) {
+ if (!detect_sscape(sscape, wss_port[dev])) {
printk(KERN_ERR "sscape: hardware not detected at 0x%x\n", sscape->io_base);
err = -ENODEV;
goto _release_dma;
@@ -1288,12 +1176,11 @@ static int __devinit create_sscape(int dev, struct snd_card *card)
}
#define MIDI_DEVNUM 0
if (sscape->type != SSCAPE_VIVO) {
- err = create_mpu401(card, MIDI_DEVNUM,
- MPU401_IO(xport), mpu_irq[dev]);
+ err = create_mpu401(card, MIDI_DEVNUM, port[dev], mpu_irq[dev]);
if (err < 0) {
printk(KERN_ERR "sscape: Failed to create "
- "MPU-401 device at 0x%x\n",
- MPU401_IO(xport));
+ "MPU-401 device at 0x%lx\n",
+ port[dev]);
goto _release_dma;
}
@@ -1357,10 +1244,10 @@ static int __devinit snd_sscape_probe(struct device *pdev, unsigned int dev)
struct soundscape *sscape;
int ret;
- card = snd_card_new(index[dev], id[dev], THIS_MODULE,
- sizeof(struct soundscape));
- if (!card)
- return -ENOMEM;
+ ret = snd_card_create(index[dev], id[dev], THIS_MODULE,
+ sizeof(struct soundscape), &card);
+ if (ret < 0)
+ return ret;
sscape = get_card_soundscape(card);
sscape->type = SSCAPE;
@@ -1462,10 +1349,10 @@ static int __devinit sscape_pnp_detect(struct pnp_card_link *pcard,
* Create a new ALSA sound card entry, in anticipation
* of detecting our hardware ...
*/
- card = snd_card_new(index[idx], id[idx], THIS_MODULE,
- sizeof(struct soundscape));
- if (!card)
- return -ENOMEM;
+ ret = snd_card_create(index[idx], id[idx], THIS_MODULE,
+ sizeof(struct soundscape), &card);
+ if (ret < 0)
+ return ret;
sscape = get_card_soundscape(card);
diff --git a/sound/isa/wavefront/wavefront.c b/sound/isa/wavefront/wavefront.c
index 4c095bc7c72..a34ae7b1f7d 100644
--- a/sound/isa/wavefront/wavefront.c
+++ b/sound/isa/wavefront/wavefront.c
@@ -338,15 +338,16 @@ snd_wavefront_free(struct snd_card *card)
}
}
-static struct snd_card *snd_wavefront_card_new(int dev)
+static int snd_wavefront_card_new(int dev, struct snd_card **cardp)
{
struct snd_card *card;
snd_wavefront_card_t *acard;
+ int err;
- card = snd_card_new (index[dev], id[dev], THIS_MODULE,
- sizeof(snd_wavefront_card_t));
- if (card == NULL)
- return NULL;
+ err = snd_card_create(index[dev], id[dev], THIS_MODULE,
+ sizeof(snd_wavefront_card_t), &card);
+ if (err < 0)
+ return err;
acard = card->private_data;
acard->wavefront.irq = -1;
@@ -357,7 +358,8 @@ static struct snd_card *snd_wavefront_card_new(int dev)
acard->wavefront.card = card;
card->private_free = snd_wavefront_free;
- return card;
+ *cardp = card;
+ return 0;
}
static int __devinit
@@ -551,11 +553,11 @@ static int __devinit snd_wavefront_isa_match(struct device *pdev,
return 0;
#endif
if (cs4232_pcm_port[dev] == SNDRV_AUTO_PORT) {
- snd_printk("specify CS4232 port\n");
+ snd_printk(KERN_ERR "specify CS4232 port\n");
return 0;
}
if (ics2115_port[dev] == SNDRV_AUTO_PORT) {
- snd_printk("specify ICS2115 port\n");
+ snd_printk(KERN_ERR "specify ICS2115 port\n");
return 0;
}
return 1;
@@ -567,9 +569,9 @@ static int __devinit snd_wavefront_isa_probe(struct device *pdev,
struct snd_card *card;
int err;
- card = snd_wavefront_card_new(dev);
- if (! card)
- return -ENOMEM;
+ err = snd_wavefront_card_new(dev, &card);
+ if (err < 0)
+ return err;
snd_card_set_dev(card, pdev);
if ((err = snd_wavefront_probe(card, dev)) < 0) {
snd_card_free(card);
@@ -616,9 +618,9 @@ static int __devinit snd_wavefront_pnp_detect(struct pnp_card_link *pcard,
if (dev >= SNDRV_CARDS)
return -ENODEV;
- card = snd_wavefront_card_new(dev);
- if (! card)
- return -ENOMEM;
+ res = snd_wavefront_card_new(dev, &card);
+ if (res < 0)
+ return res;
if (snd_wavefront_pnp (dev, card->private_data, pcard, pid) < 0) {
if (cs4232_pcm_port[dev] == SNDRV_AUTO_PORT) {
diff --git a/sound/isa/wavefront/wavefront_synth.c b/sound/isa/wavefront/wavefront_synth.c
index 4c410820a99..beb312cca75 100644
--- a/sound/isa/wavefront/wavefront_synth.c
+++ b/sound/isa/wavefront/wavefront_synth.c
@@ -633,7 +633,7 @@ wavefront_get_sample_status (snd_wavefront_t *dev, int assume_rom)
wbuf[1] = i >> 7;
if (snd_wavefront_cmd (dev, WFC_IDENTIFY_SAMPLE_TYPE, rbuf, wbuf)) {
- snd_printk("cannot identify sample "
+ snd_printk(KERN_WARNING "cannot identify sample "
"type of slot %d\n", i);
dev->sample_status[i] = WF_ST_EMPTY;
continue;
diff --git a/sound/isa/wss/wss_lib.c b/sound/isa/wss/wss_lib.c
index 3d6c5f2838a..5d2ba1b749a 100644
--- a/sound/isa/wss/wss_lib.c
+++ b/sound/isa/wss/wss_lib.c
@@ -181,25 +181,6 @@ static void snd_wss_wait(struct snd_wss *chip)
udelay(100);
}
-static void snd_wss_outm(struct snd_wss *chip, unsigned char reg,
- unsigned char mask, unsigned char value)
-{
- unsigned char tmp = (chip->image[reg] & mask) | value;
-
- snd_wss_wait(chip);
-#ifdef CONFIG_SND_DEBUG
- if (wss_inb(chip, CS4231P(REGSEL)) & CS4231_INIT)
- snd_printk("outm: auto calibration time out - reg = 0x%x, value = 0x%x\n", reg, value);
-#endif
- chip->image[reg] = tmp;
- if (!chip->calibrate_mute) {
- wss_outb(chip, CS4231P(REGSEL), chip->mce_bit | reg);
- wmb();
- wss_outb(chip, CS4231P(REG), tmp);
- mb();
- }
-}
-
static void snd_wss_dout(struct snd_wss *chip, unsigned char reg,
unsigned char value)
{
@@ -219,7 +200,8 @@ void snd_wss_out(struct snd_wss *chip, unsigned char reg, unsigned char value)
snd_wss_wait(chip);
#ifdef CONFIG_SND_DEBUG
if (wss_inb(chip, CS4231P(REGSEL)) & CS4231_INIT)
- snd_printk("out: auto calibration time out - reg = 0x%x, value = 0x%x\n", reg, value);
+ snd_printk(KERN_DEBUG "out: auto calibration time out "
+ "- reg = 0x%x, value = 0x%x\n", reg, value);
#endif
wss_outb(chip, CS4231P(REGSEL), chip->mce_bit | reg);
wss_outb(chip, CS4231P(REG), value);
@@ -235,7 +217,8 @@ unsigned char snd_wss_in(struct snd_wss *chip, unsigned char reg)
snd_wss_wait(chip);
#ifdef CONFIG_SND_DEBUG
if (wss_inb(chip, CS4231P(REGSEL)) & CS4231_INIT)
- snd_printk("in: auto calibration time out - reg = 0x%x\n", reg);
+ snd_printk(KERN_DEBUG "in: auto calibration time out "
+ "- reg = 0x%x\n", reg);
#endif
wss_outb(chip, CS4231P(REGSEL), chip->mce_bit | reg);
mb();
@@ -252,7 +235,7 @@ void snd_cs4236_ext_out(struct snd_wss *chip, unsigned char reg,
wss_outb(chip, CS4231P(REG), val);
chip->eimage[CS4236_REG(reg)] = val;
#if 0
- printk("ext out : reg = 0x%x, val = 0x%x\n", reg, val);
+ printk(KERN_DEBUG "ext out : reg = 0x%x, val = 0x%x\n", reg, val);
#endif
}
EXPORT_SYMBOL(snd_cs4236_ext_out);
@@ -268,7 +251,8 @@ unsigned char snd_cs4236_ext_in(struct snd_wss *chip, unsigned char reg)
{
unsigned char res;
res = wss_inb(chip, CS4231P(REG));
- printk("ext in : reg = 0x%x, val = 0x%x\n", reg, res);
+ printk(KERN_DEBUG "ext in : reg = 0x%x, val = 0x%x\n",
+ reg, res);
return res;
}
#endif
@@ -394,13 +378,16 @@ void snd_wss_mce_up(struct snd_wss *chip)
snd_wss_wait(chip);
#ifdef CONFIG_SND_DEBUG
if (wss_inb(chip, CS4231P(REGSEL)) & CS4231_INIT)
- snd_printk("mce_up - auto calibration time out (0)\n");
+ snd_printk(KERN_DEBUG
+ "mce_up - auto calibration time out (0)\n");
#endif
spin_lock_irqsave(&chip->reg_lock, flags);
chip->mce_bit |= CS4231_MCE;
timeout = wss_inb(chip, CS4231P(REGSEL));
if (timeout == 0x80)
- snd_printk("mce_up [0x%lx]: serious init problem - codec still busy\n", chip->port);
+ snd_printk(KERN_DEBUG "mce_up [0x%lx]: "
+ "serious init problem - codec still busy\n",
+ chip->port);
if (!(timeout & CS4231_MCE))
wss_outb(chip, CS4231P(REGSEL),
chip->mce_bit | (timeout & 0x1f));
@@ -419,7 +406,9 @@ void snd_wss_mce_down(struct snd_wss *chip)
#ifdef CONFIG_SND_DEBUG
if (wss_inb(chip, CS4231P(REGSEL)) & CS4231_INIT)
- snd_printk("mce_down [0x%lx] - auto calibration time out (0)\n", (long)CS4231P(REGSEL));
+ snd_printk(KERN_DEBUG "mce_down [0x%lx] - "
+ "auto calibration time out (0)\n",
+ (long)CS4231P(REGSEL));
#endif
spin_lock_irqsave(&chip->reg_lock, flags);
chip->mce_bit &= ~CS4231_MCE;
@@ -427,7 +416,9 @@ void snd_wss_mce_down(struct snd_wss *chip)
wss_outb(chip, CS4231P(REGSEL), chip->mce_bit | (timeout & 0x1f));
spin_unlock_irqrestore(&chip->reg_lock, flags);
if (timeout == 0x80)
- snd_printk("mce_down [0x%lx]: serious init problem - codec still busy\n", chip->port);
+ snd_printk(KERN_DEBUG "mce_down [0x%lx]: "
+ "serious init problem - codec still busy\n",
+ chip->port);
if ((timeout & CS4231_MCE) == 0 || !(chip->hardware & hw_mask))
return;
@@ -565,7 +556,7 @@ static unsigned char snd_wss_get_format(struct snd_wss *chip,
if (channels > 1)
rformat |= CS4231_STEREO;
#if 0
- snd_printk("get_format: 0x%x (mode=0x%x)\n", format, mode);
+ snd_printk(KERN_DEBUG "get_format: 0x%x (mode=0x%x)\n", format, mode);
#endif
return rformat;
}
@@ -587,7 +578,15 @@ static void snd_wss_calibrate_mute(struct snd_wss *chip, int mute)
chip->image[CS4231_RIGHT_INPUT]);
snd_wss_dout(chip, CS4231_LOOPBACK,
chip->image[CS4231_LOOPBACK]);
+ } else {
+ snd_wss_dout(chip, CS4231_LEFT_INPUT,
+ 0);
+ snd_wss_dout(chip, CS4231_RIGHT_INPUT,
+ 0);
+ snd_wss_dout(chip, CS4231_LOOPBACK,
+ 0xfd);
}
+
snd_wss_dout(chip, CS4231_AUX1_LEFT_INPUT,
mute | chip->image[CS4231_AUX1_LEFT_INPUT]);
snd_wss_dout(chip, CS4231_AUX1_RIGHT_INPUT,
@@ -630,7 +629,6 @@ static void snd_wss_playback_format(struct snd_wss *chip,
int full_calib = 1;
mutex_lock(&chip->mce_mutex);
- snd_wss_calibrate_mute(chip, 1);
if (chip->hardware == WSS_HW_CS4231A ||
(chip->hardware & WSS_HW_CS4232_MASK)) {
spin_lock_irqsave(&chip->reg_lock, flags);
@@ -646,6 +644,24 @@ static void snd_wss_playback_format(struct snd_wss *chip,
full_calib = 0;
}
spin_unlock_irqrestore(&chip->reg_lock, flags);
+ } else if (chip->hardware == WSS_HW_AD1845) {
+ unsigned rate = params_rate(params);
+
+ /*
+ * Program the AD1845 correctly for the playback stream.
+ * Note that we do NOT need to toggle the MCE bit because
+ * the PLAYBACK_ENABLE bit of the Interface Configuration
+ * register is set.
+ *
+ * NOTE: We seem to need to write to the MSB before the LSB
+ * to get the correct sample frequency.
+ */
+ spin_lock_irqsave(&chip->reg_lock, flags);
+ snd_wss_out(chip, CS4231_PLAYBK_FORMAT, (pdfr & 0xf0));
+ snd_wss_out(chip, AD1845_UPR_FREQ_SEL, (rate >> 8) & 0xff);
+ snd_wss_out(chip, AD1845_LWR_FREQ_SEL, rate & 0xff);
+ full_calib = 0;
+ spin_unlock_irqrestore(&chip->reg_lock, flags);
}
if (full_calib) {
snd_wss_mce_up(chip);
@@ -663,7 +679,6 @@ static void snd_wss_playback_format(struct snd_wss *chip,
udelay(100); /* this seems to help */
snd_wss_mce_down(chip);
}
- snd_wss_calibrate_mute(chip, 0);
mutex_unlock(&chip->mce_mutex);
}
@@ -675,7 +690,6 @@ static void snd_wss_capture_format(struct snd_wss *chip,
int full_calib = 1;
mutex_lock(&chip->mce_mutex);
- snd_wss_calibrate_mute(chip, 1);
if (chip->hardware == WSS_HW_CS4231A ||
(chip->hardware & WSS_HW_CS4232_MASK)) {
spin_lock_irqsave(&chip->reg_lock, flags);
@@ -690,6 +704,24 @@ static void snd_wss_capture_format(struct snd_wss *chip,
full_calib = 0;
}
spin_unlock_irqrestore(&chip->reg_lock, flags);
+ } else if (chip->hardware == WSS_HW_AD1845) {
+ unsigned rate = params_rate(params);
+
+ /*
+ * Program the AD1845 correctly for the capture stream.
+ * Note that we do NOT need to toggle the MCE bit because
+ * the PLAYBACK_ENABLE bit of the Interface Configuration
+ * register is set.
+ *
+ * NOTE: We seem to need to write to the MSB before the LSB
+ * to get the correct sample frequency.
+ */
+ spin_lock_irqsave(&chip->reg_lock, flags);
+ snd_wss_out(chip, CS4231_REC_FORMAT, (cdfr & 0xf0));
+ snd_wss_out(chip, AD1845_UPR_FREQ_SEL, (rate >> 8) & 0xff);
+ snd_wss_out(chip, AD1845_LWR_FREQ_SEL, rate & 0xff);
+ full_calib = 0;
+ spin_unlock_irqrestore(&chip->reg_lock, flags);
}
if (full_calib) {
snd_wss_mce_up(chip);
@@ -714,7 +746,6 @@ static void snd_wss_capture_format(struct snd_wss *chip,
spin_unlock_irqrestore(&chip->reg_lock, flags);
snd_wss_mce_down(chip);
}
- snd_wss_calibrate_mute(chip, 0);
mutex_unlock(&chip->mce_mutex);
}
@@ -771,10 +802,11 @@ static void snd_wss_init(struct snd_wss *chip)
{
unsigned long flags;
+ snd_wss_calibrate_mute(chip, 1);
snd_wss_mce_down(chip);
#ifdef SNDRV_DEBUG_MCE
- snd_printk("init: (1)\n");
+ snd_printk(KERN_DEBUG "init: (1)\n");
#endif
snd_wss_mce_up(chip);
spin_lock_irqsave(&chip->reg_lock, flags);
@@ -789,18 +821,20 @@ static void snd_wss_init(struct snd_wss *chip)
snd_wss_mce_down(chip);
#ifdef SNDRV_DEBUG_MCE
- snd_printk("init: (2)\n");
+ snd_printk(KERN_DEBUG "init: (2)\n");
#endif
snd_wss_mce_up(chip);
spin_lock_irqsave(&chip->reg_lock, flags);
+ chip->image[CS4231_IFACE_CTRL] &= ~CS4231_AUTOCALIB;
+ snd_wss_out(chip, CS4231_IFACE_CTRL, chip->image[CS4231_IFACE_CTRL]);
snd_wss_out(chip,
CS4231_ALT_FEATURE_1, chip->image[CS4231_ALT_FEATURE_1]);
spin_unlock_irqrestore(&chip->reg_lock, flags);
snd_wss_mce_down(chip);
#ifdef SNDRV_DEBUG_MCE
- snd_printk("init: (3) - afei = 0x%x\n",
+ snd_printk(KERN_DEBUG "init: (3) - afei = 0x%x\n",
chip->image[CS4231_ALT_FEATURE_1]);
#endif
@@ -817,7 +851,7 @@ static void snd_wss_init(struct snd_wss *chip)
snd_wss_mce_down(chip);
#ifdef SNDRV_DEBUG_MCE
- snd_printk("init: (4)\n");
+ snd_printk(KERN_DEBUG "init: (4)\n");
#endif
snd_wss_mce_up(chip);
@@ -827,9 +861,10 @@ static void snd_wss_init(struct snd_wss *chip)
chip->image[CS4231_REC_FORMAT]);
spin_unlock_irqrestore(&chip->reg_lock, flags);
snd_wss_mce_down(chip);
+ snd_wss_calibrate_mute(chip, 0);
#ifdef SNDRV_DEBUG_MCE
- snd_printk("init: (5)\n");
+ snd_printk(KERN_DEBUG "init: (5)\n");
#endif
}
@@ -885,8 +920,6 @@ static void snd_wss_close(struct snd_wss *chip, unsigned int mode)
mutex_unlock(&chip->open_mutex);
return;
}
- snd_wss_calibrate_mute(chip, 1);
-
/* disable IRQ */
spin_lock_irqsave(&chip->reg_lock, flags);
if (!(chip->hardware & WSS_HW_AD1848_MASK))
@@ -919,8 +952,6 @@ static void snd_wss_close(struct snd_wss *chip, unsigned int mode)
wss_outb(chip, CS4231P(STATUS), 0); /* clear IRQ */
spin_unlock_irqrestore(&chip->reg_lock, flags);
- snd_wss_calibrate_mute(chip, 0);
-
chip->mode = 0;
mutex_unlock(&chip->open_mutex);
}
@@ -1113,7 +1144,7 @@ irqreturn_t snd_wss_interrupt(int irq, void *dev_id)
if (chip->hardware & WSS_HW_AD1848_MASK)
wss_outb(chip, CS4231P(STATUS), 0);
else
- snd_wss_outm(chip, CS4231_IRQ_STATUS, status, 0);
+ snd_wss_out(chip, CS4231_IRQ_STATUS, status);
spin_unlock(&chip->reg_lock);
return IRQ_HANDLED;
}
@@ -1278,7 +1309,8 @@ static int snd_wss_probe(struct snd_wss *chip)
} else if (rev == 0x03) {
chip->hardware = WSS_HW_CS4236B;
} else {
- snd_printk("unknown CS chip with version 0x%x\n", rev);
+ snd_printk(KERN_ERR
+ "unknown CS chip with version 0x%x\n", rev);
return -ENODEV; /* unknown CS4231 chip? */
}
}
@@ -1314,6 +1346,10 @@ static int snd_wss_probe(struct snd_wss *chip)
chip->image[CS4231_ALT_FEATURE_2] =
chip->hardware == WSS_HW_INTERWAVE ? 0xc2 : 0x01;
}
+ /* enable fine grained frequency selection */
+ if (chip->hardware == WSS_HW_AD1845)
+ chip->image[AD1845_PWR_DOWN] = 8;
+
ptr = (unsigned char *) &chip->image;
regnum = (chip->hardware & WSS_HW_AD1848_MASK) ? 16 : 32;
snd_wss_mce_down(chip);
@@ -1342,7 +1378,10 @@ static int snd_wss_probe(struct snd_wss *chip)
case 6:
break;
default:
- snd_printk("unknown CS4235 chip (enhanced version = 0x%x)\n", id);
+ snd_printk(KERN_WARNING
+ "unknown CS4235 chip "
+ "(enhanced version = 0x%x)\n",
+ id);
}
} else if ((id & 0x1f) == 0x0b) { /* CS4236/B */
switch (id >> 5) {
@@ -1353,7 +1392,10 @@ static int snd_wss_probe(struct snd_wss *chip)
chip->hardware = WSS_HW_CS4236B;
break;
default:
- snd_printk("unknown CS4236 chip (enhanced version = 0x%x)\n", id);
+ snd_printk(KERN_WARNING
+ "unknown CS4236 chip "
+ "(enhanced version = 0x%x)\n",
+ id);
}
} else if ((id & 0x1f) == 0x08) { /* CS4237B */
chip->hardware = WSS_HW_CS4237B;
@@ -1364,7 +1406,10 @@ static int snd_wss_probe(struct snd_wss *chip)
case 7:
break;
default:
- snd_printk("unknown CS4237B chip (enhanced version = 0x%x)\n", id);
+ snd_printk(KERN_WARNING
+ "unknown CS4237B chip "
+ "(enhanced version = 0x%x)\n",
+ id);
}
} else if ((id & 0x1f) == 0x09) { /* CS4238B */
chip->hardware = WSS_HW_CS4238B;
@@ -1374,7 +1419,10 @@ static int snd_wss_probe(struct snd_wss *chip)
case 7:
break;
default:
- snd_printk("unknown CS4238B chip (enhanced version = 0x%x)\n", id);
+ snd_printk(KERN_WARNING
+ "unknown CS4238B chip "
+ "(enhanced version = 0x%x)\n",
+ id);
}
} else if ((id & 0x1f) == 0x1e) { /* CS4239 */
chip->hardware = WSS_HW_CS4239;
@@ -1384,10 +1432,15 @@ static int snd_wss_probe(struct snd_wss *chip)
case 6:
break;
default:
- snd_printk("unknown CS4239 chip (enhanced version = 0x%x)\n", id);
+ snd_printk(KERN_WARNING
+ "unknown CS4239 chip "
+ "(enhanced version = 0x%x)\n",
+ id);
}
} else {
- snd_printk("unknown CS4236/CS423xB chip (enhanced version = 0x%x)\n", id);
+ snd_printk(KERN_WARNING
+ "unknown CS4236/CS423xB chip "
+ "(enhanced version = 0x%x)\n", id);
}
}
}
@@ -1618,7 +1671,8 @@ static void snd_wss_resume(struct snd_wss *chip)
wss_outb(chip, CS4231P(REGSEL), chip->mce_bit | (timeout & 0x1f));
spin_unlock_irqrestore(&chip->reg_lock, flags);
if (timeout == 0x80)
- snd_printk("down [0x%lx]: serious init problem - codec still busy\n", chip->port);
+ snd_printk(KERN_ERR "down [0x%lx]: serious init problem "
+ "- codec still busy\n", chip->port);
if ((timeout & CS4231_MCE) == 0 ||
!(chip->hardware & (WSS_HW_CS4231_MASK | WSS_HW_CS4232_MASK))) {
return;
@@ -1628,7 +1682,7 @@ static void snd_wss_resume(struct snd_wss *chip)
}
#endif /* CONFIG_PM */
-static int snd_wss_free(struct snd_wss *chip)
+int snd_wss_free(struct snd_wss *chip)
{
release_and_free_resource(chip->res_port);
release_and_free_resource(chip->res_cport);
@@ -1651,6 +1705,7 @@ static int snd_wss_free(struct snd_wss *chip)
kfree(chip);
return 0;
}
+EXPORT_SYMBOL(snd_wss_free);
static int snd_wss_dev_free(struct snd_device *device)
{
@@ -1820,7 +1875,8 @@ int snd_wss_create(struct snd_card *card,
#if 0
if (chip->hardware & WSS_HW_CS4232_MASK) {
if (chip->res_cport == NULL)
- snd_printk("CS4232 control port features are not accessible\n");
+ snd_printk(KERN_ERR "CS4232 control port features are "
+ "not accessible\n");
}
#endif