diff options
Diffstat (limited to 'drivers/sound/sgalaxy.c')
-rw-r--r-- | drivers/sound/sgalaxy.c | 190 |
1 files changed, 190 insertions, 0 deletions
diff --git a/drivers/sound/sgalaxy.c b/drivers/sound/sgalaxy.c new file mode 100644 index 000000000..4e5cb870e --- /dev/null +++ b/drivers/sound/sgalaxy.c @@ -0,0 +1,190 @@ +/* + * sound/sgalaxy.c + * + * Low level driver for Aztech Sound Galaxy cards. + * Copyright 1998 Artur Skawina + * + * Supported cards: + * Aztech Sound Galaxy Waverider Pro 32 - 3D + * Aztech Sound Galaxy Washington 16 + * + * Based on cs4232.c by Hannu Savolainen and Alan Cox. + */ +/* + * Copyright (C) by Hannu Savolainen 1993-1997 + * + * OSS/Free for Linux is distributed under the GNU GENERAL PUBLIC LICENSE (GPL) + * Version 2 (June 1991). See the "COPYING" file distributed with this software + * for more info. + */ + +#include <linux/config.h> +#include <linux/module.h> + +#include "sound_config.h" +#include "soundmodule.h" + +#if defined(CONFIG_SGALAXY) || defined (MODULE) + +static void sleep( unsigned howlong ) +{ + current->state = TASK_INTERRUPTIBLE; + current->timeout = jiffies + howlong; + schedule(); + current->timeout = 0; +} + +#define DPORT 0x80 + +/* Sound Blaster regs */ + +#define SBDSP_RESET 0x6 +#define SBDSP_READ 0xA +#define SBDSP_COMMAND 0xC +#define SBDSP_STATUS SBDSP_COMMAND +#define SBDSP_DATA_AVAIL 0xE + +static int sb_rst(int base) +{ + int i; + + outb( 1, base+SBDSP_RESET ); /* reset the DSP */ + outb( 0, base+SBDSP_RESET ); + + for ( i=0; i<500; i++ ) /* delay */ + inb(DPORT); + + for ( i=0; i<100000; i++ ) + { + if ( inb( base+SBDSP_DATA_AVAIL )&0x80 ) + break; + } + + if ( inb( base+SBDSP_READ )!=0xAA ) + return 0; + + return 1; +} + +static int sb_cmd( int base, unsigned char val ) +{ + int i; + + for ( i=100000; i; i-- ) + { + if ( (inb( base+SBDSP_STATUS )&0x80)==0 ) + { + outb( val, base+SBDSP_COMMAND ); + break; + } + } + return i; /* i>0 == success */ +} + + +#define ai_sgbase driver_use_1 + +int probe_sgalaxy( struct address_info *ai ) +{ + if ( check_region( ai->io_base, 8 ) ) + { + printk(KERN_ERR "sgalaxy: WSS IO port 0x%03x not available\n", ai->io_base); + return 0; + } + + if ( ad1848_detect( ai->io_base+4, NULL, ai->osp ) ) + return 1; /* The card is already active */ + + if ( check_region( ai->ai_sgbase, 0x10 ) ) + { + printk(KERN_ERR "sgalaxy: SB IO port 0x%03x not available\n", ai->ai_sgbase); + return 0; + } + + /* switch to MSS/WSS mode */ + + sb_rst( ai->ai_sgbase ); + + sb_cmd( ai->ai_sgbase, 9 ); + sb_cmd( ai->ai_sgbase, 0 ); + + sleep( HZ/10 ); + + if ( ad1848_detect( ai->io_base+4, NULL, ai->osp ) ) + return 1; + return 0; +} + +void attach_sgalaxy( struct address_info *ai ) +{ + int n; + + request_region( ai->ai_sgbase, 0x10, "SoundGalaxy SB" ); + + attach_ms_sound( ai ); + n=ai->slots[0]; + + if (n!=-1 && audio_devs[n]->mixer_dev != -1 ) + { + AD1848_REROUTE( SOUND_MIXER_LINE1, SOUND_MIXER_LINE ); /* Line-in */ + AD1848_REROUTE( SOUND_MIXER_LINE2, SOUND_MIXER_SYNTH ); /* FM+Wavetable*/ + AD1848_REROUTE( SOUND_MIXER_LINE3, SOUND_MIXER_CD ); /* CD */ + } +} + +void unload_sgalaxy( struct address_info *ai ) +{ + unload_ms_sound( ai ); + release_region( ai->ai_sgbase, 0x10 ); +} + +#ifdef MODULE + +int io = -1; +int irq = -1; +int dma = -1; +int dma2 = -1; +int sgbase = -1; + +MODULE_PARM(io,"i"); +MODULE_PARM(irq,"i"); +MODULE_PARM(dma,"i"); +MODULE_PARM(dma2,"i"); +MODULE_PARM(sgbase,"i"); + +EXPORT_NO_SYMBOLS; + +struct address_info ai; + + +int init_module(void) +{ + if ( io==-1 || irq==-1 || dma==-1 || sgbase==-1 ) + { + printk(KERN_ERR "sgalaxy: io, irq, dma and sgbase must be set.\n"); + return -EINVAL; + } + + ai.io_base = io; + ai.irq = irq; + ai.dma = dma; + ai.dma2 = dma2; + ai.ai_sgbase = sgbase; + + if ( probe_sgalaxy( &ai )==0 ) + return -ENODEV; + + attach_sgalaxy( &ai ); + + SOUND_LOCK; + return 0; +} + +void cleanup_module(void) +{ + unload_sgalaxy( &ai ); + SOUND_LOCK_END; +} + +#endif +#endif |