Pull acpi_bus_register_driver into release branch
[linux-2.6] / 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         struct resource *ports;
90         int n;
91
92         if (!request_region(ai->io_base, 4, "WSS config")) {
93                 printk(KERN_ERR "sgalaxy: WSS IO port 0x%03x not available\n", ai->io_base);
94                 return 0;
95         }
96
97         ports = request_region(ai->io_base + 4, 4, "ad1848");
98         if (!ports) {
99                 printk(KERN_ERR "sgalaxy: WSS IO port 0x%03x not available\n", ai->io_base);
100                 release_region(ai->io_base, 4);
101                 return 0;
102         }
103
104         if (!request_region( ai->ai_sgbase, 0x10, "SoundGalaxy SB")) {
105                 printk(KERN_ERR "sgalaxy: SB IO port 0x%03x not available\n", ai->ai_sgbase);
106                 release_region(ai->io_base + 4, 4);
107                 release_region(ai->io_base, 4);
108                 return 0;
109         }
110         
111         if (ad1848_detect(ports, NULL, ai->osp))
112                 goto out;  /* The card is already active, check irq etc... */
113         
114         /* switch to MSS/WSS mode */
115    
116         sb_rst( ai->ai_sgbase );
117    
118         sb_cmd( ai->ai_sgbase, 9 );
119         sb_cmd( ai->ai_sgbase, 0 );
120
121         sleep( HZ/10 );
122
123 out:
124         if (!probe_ms_sound(ai, ports)) {
125                 release_region(ai->io_base + 4, 4);
126                 release_region(ai->io_base, 4);
127                 release_region(ai->ai_sgbase, 0x10);
128                 return 0;
129         }
130
131         attach_ms_sound(ai, ports, THIS_MODULE);
132         n=ai->slots[0];
133         
134         if (n!=-1 && audio_devs[n]->mixer_dev != -1 ) {
135                 AD1848_REROUTE( SOUND_MIXER_LINE1, SOUND_MIXER_LINE );   /* Line-in */
136                 AD1848_REROUTE( SOUND_MIXER_LINE2, SOUND_MIXER_SYNTH );  /* FM+Wavetable*/
137                 AD1848_REROUTE( SOUND_MIXER_LINE3, SOUND_MIXER_CD );     /* CD */
138         }
139         return 1;
140 }
141
142 static void __exit unload_sgalaxy( struct address_info *ai )
143 {
144         unload_ms_sound( ai );
145         release_region( ai->ai_sgbase, 0x10 );
146 }
147
148 static struct address_info cfg;
149
150 static int __initdata io        = -1;
151 static int __initdata irq       = -1;
152 static int __initdata dma       = -1;
153 static int __initdata dma2      = -1;
154 static int __initdata sgbase    = -1;
155
156 module_param(io, int, 0);
157 module_param(irq, int, 0);
158 module_param(dma, int, 0);
159 module_param(dma2, int, 0);
160 module_param(sgbase, int, 0);
161
162 static int __init init_sgalaxy(void)
163 {
164         cfg.io_base   = io;
165         cfg.irq       = irq;
166         cfg.dma       = dma;
167         cfg.dma2      = dma2;
168         cfg.ai_sgbase = sgbase;
169
170         if (cfg.io_base == -1 || cfg.irq == -1 || cfg.dma == -1 || cfg.ai_sgbase == -1 ) {
171                 printk(KERN_ERR "sgalaxy: io, irq, dma and sgbase must be set.\n");
172                 return -EINVAL;
173         }
174
175         if ( probe_sgalaxy(&cfg) == 0 )
176                 return -ENODEV;
177
178         return 0;
179 }
180
181 static void __exit cleanup_sgalaxy(void)
182 {
183         unload_sgalaxy(&cfg);
184 }
185
186 module_init(init_sgalaxy);
187 module_exit(cleanup_sgalaxy);
188
189 #ifndef MODULE
190 static int __init setup_sgalaxy(char *str)
191 {
192         /* io, irq, dma, dma2, sgbase */
193         int ints[6];
194         
195         str = get_options(str, ARRAY_SIZE(ints), ints);
196         io      = ints[1];
197         irq     = ints[2];
198         dma     = ints[3];
199         dma2    = ints[4];
200         sgbase  = ints[5];
201
202         return 1;
203 }
204
205 __setup("sgalaxy=", setup_sgalaxy);
206 #endif
207 MODULE_LICENSE("GPL");