Commit | Line | Data |
---|---|---|
1da177e4 LT |
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"); |