[alsa-devel] [PATCH] New Aztech Sound Galaxy driver.
Good day.
This is not being submitted yet...
This is a new driver for Aztech Sound Galaxy soundcards. At the moment, it supports all AZT2316A/R based cards which make up the bulk of SG cards. It's been tested and found to be working with:
1. FCC-ID I38-MMSN824: Aztech Sound Galaxy Pro 16 AB 2. FCC-ID I38-MMSN826: Aztech Sound Galaxy Waverider 32+ 3. FCC-ID I38-MMSN830: Trust Sound Expert DeLuxe 16+ 4. FCC-ID I38-MMSN847: Trust Sound Expert DeLuxe Wave 32-3D 5. FCC-ID I38-MMSN852: Aztech Sound Galaxy Waverider Pro 32-3D
where:
1. I38-MMSN824 = AZT2316A + CS4248-KL, without EEPROM 2. I38-MMSN826 = AZT2316A + AD1845XP, with EEPROM 3. I38-MMSN830 = AZT2316A + CS4248-KL, without EEPROM, and some cards: AZT2316A + AD1845-XP, without EEPROM 4. I38-MMSN847 = AZT2316R + CS4231A-KL, with EEPROM 5. I38-MMSN852 = AZT2316R + CS4231A-KL, with EEPROM
All cards with a settings EEPROM have been tested with their JMPCFG jumper set to both EEPROM and SOFTWARE, and work correctly in both situations.
All cards support full-duplex. The ones with AD1845XP codecs seem to be a little flakey, where starting a capture _sometimes_ hangs a concurrent playback, and sometimes not.
Except the ones with a CS4248-KL codec, all cards experience a "cs4231_mce_down - auto calibration time out (1)" upon loading which does not seem to have any further consequences. Both this and the previous point may be cause for debugging cs4231_lib. Later...
Ram -- included you in the CC because you had a:
FCC-ID: I38-MMSN846: Aztech Sound Galaxy Nova 16 Extra II-3D, AZT2316R + CS4231A-KL, without EEPROM
The attached patch is against 2.6.22.x and if you're setup to test, feel free and I'll add your card to the "was tested on" list. If you're not, don't bother too much though -- it'll work (and sorry for the long delay by the way...).
As to the AZT2316A/R chipset series, this driver seems complete and correct. I also have a couple of Aztech Sound Galaxy cards with an AZT1605 chipset (and one even older Sound Galaxy) though and those don't quite/fully work yet as their EEPROMs are layed out slightly different -- they also store default volumes in the EEPROM for example. Got about half of it mapped out already but can't work on it tomorrow so thought I'd post now.
Finally I have a bunch of AZT2320 based cards, which are PnP based, and which I'll merge in as well.
Krzysztof -- you won't be surprised to learn that this driver doesn't do auto-probing. It needs all parameters passed in; normally:
options snd-galaxy port=0x220 wss_port=0x530 irq=10 dma1=1 dma2=0
If you don't specify dma2 (or set it equal to dma1) the card's setup in half-duplex mode. I'll document it all upon driver submission. Your (expected) Waverider should also work fine with it. If/when you test it, could you provide the information such as given in the tables above?
You have an EEPROM if you have "X24C00" chip sitting on a spot marked "UX2" on the board, close to a crystal (silver shiny thing). If that spot is empty, you have an EEPROM-less variant.
Mapping out the rest of AZT1605 (there may also be a duplex diference there) will be sunday or next week.
Rene.
diff --git a/sound/isa/Kconfig b/sound/isa/Kconfig index cf3803c..02a0f55 100644 --- a/sound/isa/Kconfig +++ b/sound/isa/Kconfig @@ -177,6 +177,19 @@ config SND_ES18XX To compile this driver as a module, choose M here: the module will be called snd-es18xx.
+config SND_GALAXY + tristate "Aztech Sound Galaxy Driver" + depends on SND + select SND_CS4231_LIB + select SND_MPU401_UART + select SND_OPL3_LIB + select SND_PCM + help + Say Y here to include support for Aztech Sound Galaxy cards. + + To compile this driver as a module, choose M here: the module + will be called snd-galaxy. + config SND_GUS_SYNTH tristate
diff --git a/sound/isa/Makefile b/sound/isa/Makefile index bb317cc..28bf545 100644 --- a/sound/isa/Makefile +++ b/sound/isa/Makefile @@ -12,6 +12,7 @@ snd-es18xx-objs := es18xx.o snd-opl3sa2-objs := opl3sa2.o snd-sgalaxy-objs := sgalaxy.o snd-sscape-objs := sscape.o +snd-galaxy-objs := galaxy.o
# Toplevel Module Dependency obj-$(CONFIG_SND_ADLIB) += snd-adlib.o @@ -23,6 +24,7 @@ obj-$(CONFIG_SND_ES18XX) += snd-es18xx.o obj-$(CONFIG_SND_OPL3SA2) += snd-opl3sa2.o obj-$(CONFIG_SND_SGALAXY) += snd-sgalaxy.o obj-$(CONFIG_SND_SSCAPE) += snd-sscape.o +obj-$(CONFIG_SND_GALAXY) += snd-galaxy.o
obj-$(CONFIG_SND) += ad1816a/ ad1848/ cs423x/ es1688/ gus/ opti9xx/ \ sb/ wavefront/ diff --git a/sound/isa/galaxy.c b/sound/isa/galaxy.c new file mode 100644 index 0000000..8f8e9af --- /dev/null +++ b/sound/isa/galaxy.c @@ -0,0 +1,674 @@ +/* + * Aztech Sound Galaxy Driver + */ + +#include <sound/driver.h> +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/isa.h> +#include <linux/delay.h> +#include <asm/io.h> +#include <sound/core.h> +#include <sound/initval.h> +#include <sound/cs4231.h> +#include <sound/mpu401.h> +#include <sound/opl3.h> + +#define CRD_NAME "Aztech Sound Galaxy" +#define DRV_NAME "GALAXY" +#define DEV_NAME "galaxy" + +MODULE_DESCRIPTION(CRD_NAME); +MODULE_AUTHOR("Rene Herman"); +MODULE_LICENSE("GPL"); + +static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX; +static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR; +static int enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE; + +module_param_array(index, int, NULL, 0444); +MODULE_PARM_DESC(index, "Index value for " CRD_NAME " soundcard."); +module_param_array(id, charp, NULL, 0444); +MODULE_PARM_DESC(id, "ID string for " CRD_NAME " soundcard."); +module_param_array(enable, bool, NULL, 0444); +MODULE_PARM_DESC(enable, "Enable " CRD_NAME " soundcard."); + +static long port[SNDRV_CARDS] = SNDRV_DEFAULT_PORT; +static long wss_port[SNDRV_CARDS] = SNDRV_DEFAULT_PORT; +static long mpu_port[SNDRV_CARDS] = SNDRV_DEFAULT_PORT; +static long fm_port[SNDRV_CARDS] = SNDRV_DEFAULT_PORT; +static int irq[SNDRV_CARDS] = SNDRV_DEFAULT_IRQ; +static int mpu_irq[SNDRV_CARDS] = SNDRV_DEFAULT_IRQ; +static int dma1[SNDRV_CARDS] = SNDRV_DEFAULT_DMA; +static int dma2[SNDRV_CARDS] = SNDRV_DEFAULT_DMA; + +module_param_array(port, long, NULL, 0444); +MODULE_PARM_DESC(port, "Port # for " CRD_NAME " driver."); +module_param_array(wss_port, long, NULL, 0444); +MODULE_PARM_DESC(wss_port, "WSS 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(fm_port, long, NULL, 0444); +MODULE_PARM_DESC(fm_port, "OPL3 port # for " CRD_NAME " driver."); +module_param_array(irq, int, NULL, 0444); +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."); +module_param_array(dma1, int, NULL, 0444); +MODULE_PARM_DESC(dma1, "Playback DMA # for " CRD_NAME " driver."); +module_param_array(dma2, int, NULL, 0444); +MODULE_PARM_DESC(dma2, "Capture DMA # for " CRD_NAME " driver."); + +/* + * Sound Galaxy 32-bit serial EEPROM + */ + +#define GALAXY_PORT_CONFIG 1024 + +#define GALAXY_CONFIG_SBDMA_DISABLE (0 << 30) +#define GALAXY_CONFIG_SBDMA_0 (1 << 30) +#define GALAXY_CONFIG_SBDMA_1 (2 << 30) +#define GALAXY_CONFIG_SBDMA_3 (3 << 30) + +#define GALAXY_CONFIG_SBIRQ_10 (1 << 29) +#define GALAXY_CONFIG_SBIRQ_7 (1 << 28) +#define GALAXY_CONFIG_SBIRQ_5 (1 << 27) +#define GALAXY_CONFIG_SBIRQ_2 (1 << 26) + +#define GALAXY_CONFIG_SBA_220 (0 << 24) +#define GALAXY_CONFIG_SBA_240 (1 << 24) +#define GALAXY_CONFIG_SBA_260 (2 << 24) +#define GALAXY_CONFIG_SBA_280 (3 << 24) +#define GALAXY_CONFIG_SBA_MASK GALAXY_CONFIG_SBA_280 + +#define GALAXY_CONFIG_CDA_310 (0 << 22) +#define GALAXY_CONFIG_CDA_320 (1 << 22) +#define GALAXY_CONFIG_CDA_340 (2 << 22) +#define GALAXY_CONFIG_CDA_350 (3 << 22) +#define GALAXY_CONFIG_CDA_MASK GALAXY_CONFIG_CDA_350 + +#define GALAXY_CONFIG_MPU_ENABLE (1 << 21) +#define GALAXY_CONFIG_MPUA_300 (0 << 20) +#define GALAXY_CONFIG_MPUA_330 (1 << 20) + +#define GALAXY_CONFIG_GAME_ENABLE (1 << 19) + +#define GALAXY_CONFIG_WSS_ENABLE (1 << 18) +#define GALAXY_CONFIG_WSSA_530 (0 << 16) +#define GALAXY_CONFIG_WSSA_604 (1 << 16) +#define GALAXY_CONFIG_WSSA_E80 (2 << 16) +#define GALAXY_CONFIG_WSSA_F40 (3 << 16) + +#define GALAXY_CONFIG_CDDMA16_DISABLE (0 << 14) +#define GALAXY_CONFIG_CDDMA16_5 (1 << 14) +#define GALAXY_CONFIG_CDDMA16_6 (2 << 14) +#define GALAXY_CONFIG_CDDMA16_7 (3 << 14) +#define GALAXY_CONFIG_CDDMA16_MASK GALAXY_CONFIG_CDDMA16_7 + +#define GALAXY_CONFIG_CDDMA8_DISABLE (0 << 12) +#define GALAXY_CONFIG_CDDMA8_0 (1 << 12) +#define GALAXY_CONFIG_CDDMA8_1 (2 << 12) +#define GALAXY_CONFIG_CDDMA8_3 (3 << 12) +#define GALAXY_CONFIG_CDDMA8_MASK GALAXY_CONFIG_CDDMA8_3 + +#define GALAXY_CONFIG_CD_DISABLE (0 << 8) +#define GALAXY_CONFIG_CD_PANASONIC (1 << 8) +#define GALAXY_CONFIG_CD_SONY (2 << 8) +#define GALAXY_CONFIG_CD_MITSUMI (3 << 8) +#define GALAXY_CONFIG_CD_AZTECH (4 << 8) +#define GALAXY_CONFIG_CD_UNUSED_0 (5 << 8) +#define GALAXY_CONFIG_CD_UNUSED_1 (6 << 8) +#define GALAXY_CONFIG_CD_UNUSED_2 (7 << 8) +#define GALAXY_CONFIG_CD_MASK GALAXY_CONFIG_CD_UNUSED_2 + +#define GALAXY_CONFIG_CDIRQ_15 (1 << 7) +#define GALAXY_CONFIG_CDIRQ_12 (1 << 6) +#define GALAXY_CONFIG_CDIRQ_11 (1 << 5) +#define GALAXY_CONFIG_CDIRQ_5 (1 << 4) +#define GALAXY_CONFIG_CDIRQ_MASK (\ + GALAXY_CONFIG_CDIRQ_15 | GALAXY_CONFIG_CDIRQ_12 |\ + GALAXY_CONFIG_CDIRQ_11 | GALAXY_CONFIG_CDIRQ_5) + +#define GALAXY_CONFIG_MPUIRQ_10 (1 << 3) +#define GALAXY_CONFIG_MPUIRQ_7 (1 << 2) +#define GALAXY_CONFIG_MPUIRQ_5 (1 << 1) +#define GALAXY_CONFIG_MPUIRQ_2 (1 << 0) + +#define GALAXY_CONFIG_MASK (\ + GALAXY_CONFIG_SBA_MASK | GALAXY_CONFIG_CDA_MASK |\ + GALAXY_CONFIG_CDDMA16_MASK | GALAXY_CONFIG_CDDMA8_MASK |\ + GALAXY_CONFIG_CD_MASK | GALAXY_CONFIG_CDIRQ_MASK) + +/* + * WSS 8-bit configuration register + */ + +#define WSS_PORT_CONFIG 0 + +#define WSS_CONFIG_IRQ_7 (1 << 3) +#define WSS_CONFIG_IRQ_9 (2 << 3) +#define WSS_CONFIG_IRQ_10 (3 << 3) +#define WSS_CONFIG_IRQ_11 (4 << 3) + +#define WSS_CONFIG_DUPLEX (1 << 2) + +#define WSS_CONFIG_DMA_0 (1 << 0) +#define WSS_CONFIG_DMA_1 (2 << 0) +#define WSS_CONFIG_DMA_3 (3 << 0) + +#define WSS_PORT_SIGNATURE 3 +#define WSS_SIGNATURE 4 + +/* + * Generic SB DSP registers + */ + +#define DSP_PORT_RESET 0x6 +#define DSP_PORT_READ 0xa +#define DSP_PORT_COMMAND 0xc +#define DSP_PORT_STATUS 0xc +#define DSP_PORT_DATA_AVAIL 0xe + +#define DSP_SIGNATURE 0xaa + +/* + * Sound Galaxy specific DSP commands. + */ + +#define DSP_COMMAND_GALAXY 9 + +#define GALAXY_COMMAND_WSSMODE 0 +#define GALAXY_COMMAND_SBPMODE 1 +#define GALAXY_COMMAND_MPU 2 +#define GALAXY_COMMAND_MPUA 4 + +#define GALAXY_MODE_WSS GALAXY_COMMAND_WSSMODE +#define GALAXY_MODE_SBP GALAXY_COMMAND_SBPMODE + +struct snd_galaxy { + void __iomem *port; + void __iomem *config_port; + void __iomem *wss_port; + struct resource *res_port; + struct resource *res_config_port; + struct resource *res_wss_port; + u32 config; +}; + +static u32 config[SNDRV_CARDS]; +static u8 wss_config[SNDRV_CARDS]; + +static int __devinit snd_galaxy_match(struct device *dev, unsigned int n) +{ + if (!enable[n]) + return 0; + + switch (port[n]) { + case SNDRV_AUTO_PORT: + snd_printk(KERN_ERR "%s: please specify port\n", dev->bus_id); + return 0; + case 0x220: + config[n] |= GALAXY_CONFIG_SBA_220; + break; + case 0x240: + config[n] |= GALAXY_CONFIG_SBA_240; + break; + default: + snd_printk(KERN_ERR "%s: invalid port %#lx\n", dev->bus_id, + port[n]); + return 0; + } + + switch (wss_port[n]) { + case SNDRV_AUTO_PORT: + snd_printk(KERN_ERR "%s: please specify wss_port\n", + dev->bus_id); + return 0; + case 0x530: + config[n] |= GALAXY_CONFIG_WSS_ENABLE | GALAXY_CONFIG_WSSA_530; + break; + case 0x604: + config[n] |= GALAXY_CONFIG_WSS_ENABLE | GALAXY_CONFIG_WSSA_604; + break; + case 0xe80: + config[n] |= GALAXY_CONFIG_WSS_ENABLE | GALAXY_CONFIG_WSSA_E80; + break; + case 0xf40: + config[n] |= GALAXY_CONFIG_WSS_ENABLE | GALAXY_CONFIG_WSSA_F40; + break; + default: + snd_printk(KERN_ERR "%s: invalid WSS port %#lx\n", dev->bus_id, + wss_port[n]); + return 0; + } + + switch (irq[n]) { + case SNDRV_AUTO_IRQ: + snd_printk(KERN_ERR "%s: please specify irq\n", dev->bus_id); + return 0; + case 7: + wss_config[n] |= WSS_CONFIG_IRQ_7; + break; + case 9: + case 2: + wss_config[n] |= WSS_CONFIG_IRQ_9; + break; + case 10: + wss_config[n] |= WSS_CONFIG_IRQ_10; + break; + case 11: + wss_config[n] |= WSS_CONFIG_IRQ_11; + break; + default: + snd_printk(KERN_ERR "%s: invalid IRQ %d\n", dev->bus_id, + irq[n]); + return 0; + } + + switch (dma1[n]) { + case SNDRV_AUTO_DMA: + snd_printk(KERN_ERR "%s: please specify dma1\n", + dev->bus_id); + return 0; + case 0: + wss_config[n] |= WSS_CONFIG_DMA_0; + break; + case 1: + wss_config[n] |= WSS_CONFIG_DMA_1; + break; + case 3: + wss_config[n] |= WSS_CONFIG_DMA_3; + break; + default: + snd_printk(KERN_ERR "%s: invalid playback DMA %d\n", + dev->bus_id, dma1[n]); + return 0; + } + + if (dma2[n] == SNDRV_AUTO_DMA || dma2[n] == dma1[n]) { + dma2[n] = -1; + goto mpu; + } + + wss_config[n] |= WSS_CONFIG_DUPLEX; + switch (dma2[n]) { + case 1: + if (dma1[n] == 0) + case 0: + break; + default: + snd_printk(KERN_ERR "%s: invalid capture DMA %d\n", + dev->bus_id, dma2[n]); + return 0; + } + +mpu: + switch (mpu_port[n]) { + case SNDRV_AUTO_PORT: + snd_printk(KERN_WARNING "%s: mpu_port not specified; not using " + "MPU-401\n", dev->bus_id); + mpu_port[n] = -1; + goto fm; + case 0x300: + config[n] |= GALAXY_CONFIG_MPU_ENABLE | GALAXY_CONFIG_MPUA_300; + break; + case 0x330: + config[n] |= GALAXY_CONFIG_MPU_ENABLE | GALAXY_CONFIG_MPUA_330; + break; + default: + snd_printk(KERN_ERR "%s: invalid mpu port %#lx\n", dev->bus_id, + mpu_port[n]); + return 0; + } + + if (mpu_irq[n] == irq[n]) { + snd_printk(KERN_ERR "%s: cannot share IRQ between WSS and " + "MPU-401\n", dev->bus_id); + return 0; + } + + switch (mpu_irq[n]) { + case SNDRV_AUTO_IRQ: + snd_printk(KERN_WARNING "%s: mpu_irq not specified; using " + "polling mode\n", dev->bus_id); + mpu_irq[n] = -1; + break; + case 2: + case 9: + config[n] |= GALAXY_CONFIG_MPUIRQ_2; + break; + case 5: + config[n] |= GALAXY_CONFIG_MPUIRQ_5; + break; + case 7: + config[n] |= GALAXY_CONFIG_MPUIRQ_7; + break; + case 10: + config[n] |= GALAXY_CONFIG_MPUIRQ_10; + break; + default: + snd_printk(KERN_ERR "%s: invalid mpu irq %d\n", dev->bus_id, + irq[n]); + return 0; + } + +fm: + switch (fm_port[n]) { + case SNDRV_AUTO_PORT: + snd_printk(KERN_WARNING "%s: fm_port not specified: not using " + "OPL3\n", dev->bus_id); + fm_port[n] = -1; + break; + case 0x388: + break; + default: + snd_printk(KERN_ERR "%s: illegal fm port %#lx\n", dev->bus_id, + fm_port[n]); + return 0; + } + + config[n] |= GALAXY_CONFIG_GAME_ENABLE; + return 1; +} + +static int __devinit __reset(struct snd_galaxy *galaxy) +{ + unsigned long timeout = jiffies + msecs_to_jiffies(100); + + iowrite8(1, galaxy->port + DSP_PORT_RESET); + udelay(10); + iowrite8(0, galaxy->port + DSP_PORT_RESET); + udelay(10); + + while (!(ioread8(galaxy->port + DSP_PORT_DATA_AVAIL) & 0x80)) { + if (time_after(jiffies, timeout)) + return -EIO; + cpu_relax(); + } + if (ioread8(galaxy->port + DSP_PORT_READ) != DSP_SIGNATURE) + return -ENODEV; + + return 0; +} + +static int __devinit __command(struct snd_galaxy *galaxy, unsigned char cmd) +{ + unsigned long timeout = jiffies + msecs_to_jiffies(100); + + while (ioread8(galaxy->port + DSP_PORT_STATUS) & 0x80) { + if (time_after(jiffies, timeout)) + return -EIO; + cpu_relax(); + } + iowrite8(cmd, galaxy->port + DSP_PORT_COMMAND); + + return 0; +} + +static int __devinit snd_galaxy_set(struct snd_galaxy *galaxy, + unsigned char cmd, int set) +{ + int err; + + err = __command(galaxy, DSP_COMMAND_GALAXY); + if (err < 0) + return err; + + err = __command(galaxy, cmd); + if (err < 0) + return err; + + err = __command(galaxy, set ? 255 : 0); + + return err; +} + +static u32 __devinit __get_config(struct snd_galaxy *galaxy) +{ + return ioread32be(galaxy->config_port); +} + +static void __devinit __set_config(struct snd_galaxy *galaxy, u32 config) +{ + unsigned char tmp = ioread8(galaxy->config_port + 4); + + iowrite8(tmp | 0x80, galaxy->config_port + 4); + udelay(10); + iowrite32be(config, galaxy->config_port); + udelay(10); + iowrite8(tmp & 0x7f, galaxy->config_port + 4); +} + +static int __devinit snd_galaxy_config(struct snd_galaxy *galaxy, u32 config) +{ + int err; + + err = snd_galaxy_set(galaxy, GALAXY_COMMAND_MPU, + config & GALAXY_CONFIG_MPU_ENABLE); + if (err < 0) + return err; + + err = snd_galaxy_set(galaxy, GALAXY_COMMAND_MPUA, + config & GALAXY_CONFIG_MPUA_330); + if (err < 0) + return err; + + galaxy->config = __get_config(galaxy); + __set_config(galaxy, (galaxy->config & GALAXY_CONFIG_MASK) | config); + + msleep(100); + return 0; +} + +static int __devinit snd_galaxy_setmode(struct snd_galaxy *galaxy, int mode) +{ + int err; + + err = __reset(galaxy); + if (err < 0) + return err; + + err = __command(galaxy, DSP_COMMAND_GALAXY); + if (err < 0) + return err; + + err = __command(galaxy, mode); + if (err < 0) + return err; + + msleep(100); + return 0; +} + +static unsigned char __devinit __wss_signature(struct snd_galaxy *galaxy) +{ + return ioread8(galaxy->wss_port + WSS_PORT_SIGNATURE) & 0x3f; +} + +static void __devinit __wss_config(struct snd_galaxy *galaxy, u8 wss_config) +{ + iowrite8(wss_config, galaxy->wss_port + WSS_PORT_CONFIG); +} + +static int __devinit snd_galaxy_wss_config(struct snd_galaxy *galaxy, + u8 wss_config) +{ + if (__wss_signature(galaxy) != WSS_SIGNATURE) + return -ENODEV; + + __wss_config(galaxy, wss_config); + + msleep(100); + return 0; +} + +static void snd_galaxy_free(struct snd_card *card) +{ + struct snd_galaxy *galaxy = card->private_data; + + if (galaxy->wss_port) { + __wss_config(galaxy, 0); + ioport_unmap(galaxy->wss_port); + release_and_free_resource(galaxy->res_wss_port); + } + if (galaxy->config_port) { + __set_config(galaxy, galaxy->config); + ioport_unmap(galaxy->config_port); + release_and_free_resource(galaxy->res_config_port); + } + if (galaxy->port) { + ioport_unmap(galaxy->port); + release_and_free_resource(galaxy->res_port); + } +} + +static int __devinit snd_galaxy_probe(struct device *dev, unsigned int n) +{ + struct snd_galaxy *galaxy; + struct snd_cs4231 *chip; + struct snd_card *card; + int err; + + card = snd_card_new(index[n], id[n], THIS_MODULE, sizeof *galaxy); + if (!card) + return -EINVAL; + + snd_card_set_dev(card, dev); + + card->private_free = snd_galaxy_free; + galaxy = card->private_data; + + galaxy->res_port = request_region(port[n], 16, DRV_NAME); + if (!galaxy->res_port) { + err = -EBUSY; + goto error; + } + galaxy->port = ioport_map(port[n], 16); + + err = __reset(galaxy); + if (err < 0) { + snd_printd("%s: DSP not found at %#lx\n", dev->bus_id, port[n]); + goto error; + } + + galaxy->res_config_port = request_region(port[n] + GALAXY_PORT_CONFIG, + 16, DRV_NAME); + if (!galaxy->res_config_port) { + err = -EBUSY; + goto error; + } + galaxy->config_port = ioport_map(port[n] + GALAXY_PORT_CONFIG, 16); + + err = snd_galaxy_config(galaxy, config[n]); + if (err < 0) + goto error; + + galaxy->res_wss_port = request_region(wss_port[n], 4, DRV_NAME); + if (!galaxy->res_wss_port) { + err = -EBUSY; + goto error; + } + galaxy->wss_port = ioport_map(wss_port[n], 4); + + err = snd_galaxy_wss_config(galaxy, wss_config[n]); + if (err < 0) { + snd_printd("%s: WSS not found at %#lx\n", dev->bus_id, + wss_port[n]); + goto error; + } + + err = snd_galaxy_setmode(galaxy, GALAXY_MODE_WSS); + if (err < 0) + goto error; + + strcpy(card->driver, DRV_NAME); + strcpy(card->shortname, DRV_NAME); + + err = snd_cs4231_create(card, wss_port[n] + 4, -1, irq[n], dma1[n], + dma2[n], CS4231_HW_DETECT, 0, &chip); + if (err < 0) + return err; + + sprintf(card->longname, "%s at %#lx, irq %d, dma %d/%d", + card->shortname, chip->port, chip->irq, chip->dma1, chip->dma2); + + err = snd_cs4231_pcm(chip, 0, NULL); + if (err < 0) + return err; + + err = snd_cs4231_mixer(chip); + if (err < 0) + return err; + + err = snd_cs4231_timer(chip, 0, NULL); + if (err < 0) + return err; + + if (mpu_port[n] >= 0) { + err = snd_mpu401_uart_new(card, 0, MPU401_HW_MPU401, + mpu_port[n], 0, mpu_irq[n], + IRQF_DISABLED, NULL); + if (err < 0) + goto error; + } + + if (fm_port[n] >= 0) { + struct snd_opl3 *opl3; + + err = snd_opl3_create(card, fm_port[n], fm_port[n] + 2, + OPL3_HW_AUTO, 0, &opl3); + if (err < 0) { + snd_printk(KERN_ERR "%s: no OPL device at %#lx\n", + dev->bus_id, fm_port[n]); + goto error; + } + err = snd_opl3_timer_new(opl3, 1, 2); + if (err < 0) + goto error; + + err = snd_opl3_hwdep_new(opl3, 0, 1, NULL); + if (err < 0) + goto error; + } + + err = snd_card_register(card); + if (err < 0) + goto error; + + dev_set_drvdata(dev, card); + return 0; + +error: + snd_card_free(card); + return err; +} + +static int __devexit snd_galaxy_remove(struct device *dev, unsigned int n) +{ + snd_card_free(dev_get_drvdata(dev)); + dev_set_drvdata(dev, NULL); + return 0; +} + +static struct isa_driver snd_galaxy_driver = { + .match = snd_galaxy_match, + .probe = snd_galaxy_probe, + .remove = __devexit_p(snd_galaxy_remove), + + .driver = { + .name = DEV_NAME + } +}; + +static int __init alsa_card_galaxy_init(void) +{ + return isa_register_driver(&snd_galaxy_driver, SNDRV_CARDS); +} + +static void __exit alsa_card_galaxy_exit(void) +{ + isa_unregister_driver(&snd_galaxy_driver); +} + +module_init(alsa_card_galaxy_init); +module_exit(alsa_card_galaxy_exit);
On Sat, 08 Sep 2007 01:22:43 +0200 Rene Herman rene.herman@gmail.com wrote:
Except the ones with a CS4248-KL codec, all cards experience a "cs4231_mce_down - auto calibration time out (1)" upon loading which does not seem to have any further consequences. Both this and the previous point may be cause for debugging cs4231_lib. Later...
This is an issue I spotted in the ad1848-lib yesterday. The cs4231-lib seems little better in this respect. The driver waits for the busy bit to be set than wait until it is cleared. The first waiting is wrong because if you have a card set to no calibration (or fast calibration) code you may experience that bit is already cleared and it won't be set any more. Then the message is complete misleading. IMO, a correct solution is to wait some time. An auto-calibration takes about 348 sample periods for AD1848, so at 48KHz (fastest) it is about 7ms. Just wait that in the msleep then wait for bit to be cleared (it could be already). The code is shorter and does not rely on CPU speed (like the current ad1848-lib because it has no delay inside the loop). The 7ms may need to be changed for CS4231 (it may be faster or slower).
Krzysztof -- you won't be surprised to learn that this driver doesn't do auto-probing. It needs all parameters passed in; normally:
I think we agreed that we did not agree on this issue. It is your driver so have it your way. It is nice to have some diversity.
You have an EEPROM if you have "X24C00" chip sitting on a spot marked "UX2" on the board, close to a crystal (silver shiny thing). If that spot is empty, you have an EEPROM-less variant.
I have not received the card yet. I'll test it when I have the hardware. I am afraid it is one of cards you have already tested.
Great work - new features like waiting by cpu_relax() + jiffies and ioport_map/ioport_unmap I haven't seen in the ISA drivers.
The only thing I do not understand is that there are 4 possible addresses for the SB port base, but user can supply only the first 2.
I got your email how to set up full-duplex but it conflicts with MPU irq settings for the SC-6000 card. Another difference.
Regards, Krzysztof
On Sat, 08 Sep 2007 01:22:43 +0200 Rene Herman rene.herman@gmail.com wrote:
- I38-MMSN852 = AZT2316R + CS4231A-KL, with EEPROM
I got this one. It has also AZT3320 chip.
All cards with a settings EEPROM have been tested with their JMPCFG jumper set to both EEPROM and SOFTWARE, and work correctly in both situations.
The JMPCFG was set to software.
I run into these problems:
1. There is a problem with freeing resources in the probe function. If the probe ends with error, removal of the driver does not release requested regions, so the driver cannot be reloaded again (and cat /proc/iports crashes). It is easy to reproduce: give irq number which is already acquired by another driver then unload driver.
2. After a while I found the free irq (it took quite long with this manual settings). The driver loaded, the /proc/asound/* files showed GALAXY something but the alsamixer ended with message that there was no mixer device.
I look forward to next version of your driver to test, Krzysztof
On 09/11/2007 09:07 PM, Krzysztof Helt wrote:
- I38-MMSN852 = AZT2316R + CS4231A-KL, with EEPROM
I got this one. It has also AZT3320 chip.
Yep -- hardware midi, hooked up to the onboard MPU-401. Sounds really thin, but it's okay to play with.
- There is a problem with freeing resources in the probe function. If the probe
ends with error, removal of the driver does not release requested regions
Yes, dumb cut & paste error from when it was split off into its own function; please change the four "return err;" exits in (that version of) snd_galaxy_probe() with "goto error;"
- After a while I found the free irq (it took quite long with this
manual settings). The driver loaded, the /proc/asound/* files showed GALAXY something but the alsamixer ended with message that there was no mixer device.
It took quite long for you to look at /proc/interrupts and see which ones of four possible IRQs was unclaimed (the only thing autoprobing does)? Strange.
I don't see the mixer problem here, with the same card. Might it be a testing fluke caused by the unloading bug above?
Rene.
On 9/11/07, Rene Herman rene.herman@gmail.com wrote:
Yes, dumb cut & paste error from when it was split off into its own function; please change the four "return err;" exits in (that version of) snd_galaxy_probe() with "goto error;"
I fixed this as you wrote and now the driver works ok. I haven't tested recording.
If you care the mixer controls I found that: "Line" is CD line and "Aux1" is FM/wavetable.
This card returns DSP version 3.1 which is something better than SB Pro. Maybe these AZT-1605 cards return earlier DSP version (but I do not expect anything less than 3.0)
Regards, Krzysztof
On 09/12/2007 08:31 PM, Krzysztof Helt wrote:
I fixed this as you wrote and now the driver works ok. I haven't tested recording.
Thanks. I have been testing recording here, so that should be fine.
If you care the mixer controls I found that: "Line" is CD line and "Aux1" is FM/wavetable.
Yes, I know, and plain "Aux" is the Line In. In this case I admit it's a little clumsy since you'd expect the mixer control "Line" to be that but generally I don't much care.
Or better said, I do, and generally am not very fond of the control-renaming in the drivers since I believe ALSA should be providing for it in userspace such that the user can not only rename things to whatever the driver author and/or datasheet considered applicable, but also to things like "TV", or "Bedroom" or whatever.
This is most applicable to generic drivers -- I for example have an ES1968 card sitting in this machine with an FM Tuner connected to its "Video" input. I'd love to call that "Radio" instead...
But well, sure, maybe I'll rename them in this case. Or maybe not.
This card returns DSP version 3.1 which is something better than SB Pro. Maybe these AZT-1605 cards return earlier DSP version (but I do not expect anything less than 3.0)
They do, DSP version 2.1 and all AZT2316s I've tested are 3.1. Unfortunately though, an even older Aztech chip returns 3.1 again, meaning it's at least not going to help for integrating that as well.
Haven't had time to look at it for a few days, but will be poking again.
Rene.
participants (2)
-
Krzysztof Helt
-
Rene Herman