blob: 0bcff67353198d369624ad58bba57b86bbbb080f [file] [log] [blame]
/*
* sound/oss/sgalaxy.c
*
* Low level driver for Aztech Sound Galaxy cards.
* Copyright 1998 Artur Skawina <skawina@geocities.com>
*
* 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.
*
* Changes:
* 11-10-2000 Bartlomiej Zolnierkiewicz <bkz@linux-ide.org>
* Added __init to sb_rst() and sb_cmd()
*/
#include <linux/init.h>
#include <linux/module.h>
#include "sound_config.h"
#include "ad1848.h"
static void sleep( unsigned howlong )
{
current->state = TASK_INTERRUPTIBLE;
schedule_timeout(howlong);
}
#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 __init 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 __init 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
static int __init probe_sgalaxy( struct address_info *ai )
{
struct resource *ports;
int n;
if (!request_region(ai->io_base, 4, "WSS config")) {
printk(KERN_ERR "sgalaxy: WSS IO port 0x%03x not available\n", ai->io_base);
return 0;
}
ports = request_region(ai->io_base + 4, 4, "ad1848");
if (!ports) {
printk(KERN_ERR "sgalaxy: WSS IO port 0x%03x not available\n", ai->io_base);
release_region(ai->io_base, 4);
return 0;
}
if (!request_region( ai->ai_sgbase, 0x10, "SoundGalaxy SB")) {
printk(KERN_ERR "sgalaxy: SB IO port 0x%03x not available\n", ai->ai_sgbase);
release_region(ai->io_base + 4, 4);
release_region(ai->io_base, 4);
return 0;
}
if (ad1848_detect(ports, NULL, ai->osp))
goto out; /* The card is already active, check irq etc... */
/* 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 );
out:
if (!probe_ms_sound(ai, ports)) {
release_region(ai->io_base + 4, 4);
release_region(ai->io_base, 4);
release_region(ai->ai_sgbase, 0x10);
return 0;
}
attach_ms_sound(ai, ports, THIS_MODULE);
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 */
}
return 1;
}
static void __exit unload_sgalaxy( struct address_info *ai )
{
unload_ms_sound( ai );
release_region( ai->ai_sgbase, 0x10 );
}
static struct address_info cfg;
static int __initdata io = -1;
static int __initdata irq = -1;
static int __initdata dma = -1;
static int __initdata dma2 = -1;
static int __initdata sgbase = -1;
module_param(io, int, 0);
module_param(irq, int, 0);
module_param(dma, int, 0);
module_param(dma2, int, 0);
module_param(sgbase, int, 0);
static int __init init_sgalaxy(void)
{
cfg.io_base = io;
cfg.irq = irq;
cfg.dma = dma;
cfg.dma2 = dma2;
cfg.ai_sgbase = sgbase;
if (cfg.io_base == -1 || cfg.irq == -1 || cfg.dma == -1 || cfg.ai_sgbase == -1 ) {
printk(KERN_ERR "sgalaxy: io, irq, dma and sgbase must be set.\n");
return -EINVAL;
}
if ( probe_sgalaxy(&cfg) == 0 )
return -ENODEV;
return 0;
}
static void __exit cleanup_sgalaxy(void)
{
unload_sgalaxy(&cfg);
}
module_init(init_sgalaxy);
module_exit(cleanup_sgalaxy);
#ifndef MODULE
static int __init setup_sgalaxy(char *str)
{
/* io, irq, dma, dma2, sgbase */
int ints[6];
str = get_options(str, ARRAY_SIZE(ints), ints);
io = ints[1];
irq = ints[2];
dma = ints[3];
dma2 = ints[4];
sgbase = ints[5];
return 1;
}
__setup("sgalaxy=", setup_sgalaxy);
#endif
MODULE_LICENSE("GPL");