| /* |
| * 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"); |