ftp://ftp.kernel.org/pub/linux/kernel/v2.6/linux-2.6.6.tar.bz2
[linux-2.6.git] / sound / oss / sgalaxy.c
1 /*
2  * sound/sgalaxy.c
3  *
4  * Low level driver for Aztech Sound Galaxy cards.
5  * Copyright 1998 Artur Skawina <skawina@geocities.com>
6  *
7  * Supported cards:
8  *    Aztech Sound Galaxy Waverider Pro 32 - 3D
9  *    Aztech Sound Galaxy Washington 16
10  *
11  * Based on cs4232.c by Hannu Savolainen and Alan Cox.
12  *
13  *
14  * Copyright (C) by Hannu Savolainen 1993-1997
15  *
16  * OSS/Free for Linux is distributed under the GNU GENERAL PUBLIC LICENSE (GPL)
17  * Version 2 (June 1991). See the "COPYING" file distributed with this software
18  * for more info.
19  *
20  * Changes:
21  * 11-10-2000   Bartlomiej Zolnierkiewicz <bkz@linux-ide.org>
22  *              Added __init to sb_rst() and sb_cmd()
23  */
24
25 #include <linux/init.h>
26 #include <linux/module.h>
27
28 #include "sound_config.h"
29 #include "ad1848.h"
30
31 static void sleep( unsigned howlong )
32 {
33         current->state   = TASK_INTERRUPTIBLE;
34         schedule_timeout(howlong);
35 }
36
37 #define DPORT 0x80
38
39 /* Sound Blaster regs */
40
41 #define SBDSP_RESET      0x6
42 #define SBDSP_READ       0xA
43 #define SBDSP_COMMAND    0xC
44 #define SBDSP_STATUS     SBDSP_COMMAND
45 #define SBDSP_DATA_AVAIL 0xE
46
47 static int __init sb_rst(int base)
48 {
49         int   i;
50    
51         outb( 1, base+SBDSP_RESET );     /* reset the DSP */
52         outb( 0, base+SBDSP_RESET );
53     
54         for ( i=0; i<500; i++ )          /* delay */
55                 inb(DPORT);
56       
57         for ( i=0; i<100000; i++ )
58         {
59                 if ( inb( base+SBDSP_DATA_AVAIL )&0x80 )
60                         break;
61         }
62
63         if ( inb( base+SBDSP_READ )!=0xAA )
64                 return 0;
65
66         return 1;
67 }
68
69 static int __init sb_cmd( int base, unsigned char val )
70 {
71         int  i;
72
73         for ( i=100000; i; i-- )
74         {
75                 if ( (inb( base+SBDSP_STATUS )&0x80)==0 )
76                 {
77                         outb( val, base+SBDSP_COMMAND );
78                         break;
79                 }
80         }
81         return i;      /* i>0 == success */
82 }
83
84
85 #define ai_sgbase    driver_use_1
86
87 static int __init probe_sgalaxy( struct address_info *ai )
88 {
89         if ( check_region( ai->io_base, 8 ) ) {
90                 printk(KERN_ERR "sgalaxy: WSS IO port 0x%03x not available\n", ai->io_base);
91                 return 0;
92         }
93         
94         if ( ad1848_detect( ai->io_base+4, NULL, ai->osp ) )
95                 return probe_ms_sound(ai);  /* The card is already active, check irq etc... */
96
97         if ( check_region( ai->ai_sgbase, 0x10 ) ) {
98                 printk(KERN_ERR "sgalaxy: SB IO port 0x%03x not available\n", ai->ai_sgbase);
99                 return 0;
100         }
101         
102         /* switch to MSS/WSS mode */
103    
104         sb_rst( ai->ai_sgbase );
105    
106         sb_cmd( ai->ai_sgbase, 9 );
107         sb_cmd( ai->ai_sgbase, 0 );
108
109         sleep( HZ/10 );
110
111         return probe_ms_sound(ai);
112 }
113
114 static void __init attach_sgalaxy( struct address_info *ai )
115 {
116         int n;
117         
118         request_region( ai->ai_sgbase, 0x10, "SoundGalaxy SB" );
119  
120         attach_ms_sound(ai, THIS_MODULE);
121         n=ai->slots[0];
122         
123         if (n!=-1 && audio_devs[n]->mixer_dev != -1 ) {
124                 AD1848_REROUTE( SOUND_MIXER_LINE1, SOUND_MIXER_LINE );   /* Line-in */
125                 AD1848_REROUTE( SOUND_MIXER_LINE2, SOUND_MIXER_SYNTH );  /* FM+Wavetable*/
126                 AD1848_REROUTE( SOUND_MIXER_LINE3, SOUND_MIXER_CD );     /* CD */
127         }
128 }
129
130 static void __exit unload_sgalaxy( struct address_info *ai )
131 {
132         unload_ms_sound( ai );
133         release_region( ai->ai_sgbase, 0x10 );
134 }
135
136 static struct address_info cfg;
137
138 static int __initdata io        = -1;
139 static int __initdata irq       = -1;
140 static int __initdata dma       = -1;
141 static int __initdata dma2      = -1;
142 static int __initdata sgbase    = -1;
143
144 MODULE_PARM(io,"i");
145 MODULE_PARM(irq,"i");
146 MODULE_PARM(dma,"i");
147 MODULE_PARM(dma2,"i");
148 MODULE_PARM(sgbase,"i");
149
150 static int __init init_sgalaxy(void)
151 {
152         cfg.io_base   = io;
153         cfg.irq       = irq;
154         cfg.dma       = dma;
155         cfg.dma2      = dma2;
156         cfg.ai_sgbase = sgbase;
157
158         if (cfg.io_base == -1 || cfg.irq == -1 || cfg.dma == -1 || cfg.ai_sgbase == -1 ) {
159                 printk(KERN_ERR "sgalaxy: io, irq, dma and sgbase must be set.\n");
160                 return -EINVAL;
161         }
162
163         if ( probe_sgalaxy(&cfg) == 0 )
164                 return -ENODEV;
165
166         attach_sgalaxy(&cfg);
167
168         return 0;
169 }
170
171 static void __exit cleanup_sgalaxy(void)
172 {
173         unload_sgalaxy(&cfg);
174 }
175
176 module_init(init_sgalaxy);
177 module_exit(cleanup_sgalaxy);
178
179 #ifndef MODULE
180 static int __init setup_sgalaxy(char *str)
181 {
182         /* io, irq, dma, dma2, sgbase */
183         int ints[6];
184         
185         str = get_options(str, ARRAY_SIZE(ints), ints);
186         io      = ints[1];
187         irq     = ints[2];
188         dma     = ints[3];
189         dma2    = ints[4];
190         sgbase  = ints[5];
191
192         return 1;
193 }
194
195 __setup("sgalaxy=", setup_sgalaxy);
196 #endif
197 MODULE_LICENSE("GPL");