diff options
author | Linus Torvalds <torvalds@ppc970.osdl.org> | 2005-04-16 18:20:36 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@ppc970.osdl.org> | 2005-04-16 18:20:36 -0400 |
commit | 1da177e4c3f41524e886b7f1b8a0c1fc7321cac2 (patch) | |
tree | 0bba044c4ce775e45a88a51686b5d9f90697ea9d /sound/oss/opl3sa.c |
Linux-2.6.12-rc2v2.6.12-rc2
Initial git repository build. I'm not bothering with the full history,
even though we have it. We can create a separate "historical" git
archive of that later if we want to, and in the meantime it's about
3.2GB when imported into git - space that would just make the early
git days unnecessarily complicated, when we don't have a lot of good
infrastructure for it.
Let it rip!
Diffstat (limited to 'sound/oss/opl3sa.c')
-rw-r--r-- | sound/oss/opl3sa.c | 329 |
1 files changed, 329 insertions, 0 deletions
diff --git a/sound/oss/opl3sa.c b/sound/oss/opl3sa.c new file mode 100644 index 000000000000..fe4907c6e8fc --- /dev/null +++ b/sound/oss/opl3sa.c | |||
@@ -0,0 +1,329 @@ | |||
1 | /* | ||
2 | * sound/opl3sa.c | ||
3 | * | ||
4 | * Low level driver for Yamaha YMF701B aka OPL3-SA chip | ||
5 | * | ||
6 | * | ||
7 | * | ||
8 | * Copyright (C) by Hannu Savolainen 1993-1997 | ||
9 | * | ||
10 | * OSS/Free for Linux is distributed under the GNU GENERAL PUBLIC LICENSE (GPL) | ||
11 | * Version 2 (June 1991). See the "COPYING" file distributed with this software | ||
12 | * for more info. | ||
13 | * | ||
14 | * Changes: | ||
15 | * Alan Cox Modularisation | ||
16 | * Christoph Hellwig Adapted to module_init/module_exit | ||
17 | * Arnaldo C. de Melo got rid of attach_uart401 | ||
18 | * | ||
19 | * FIXME: | ||
20 | * Check for install of mpu etc is wrong, should check result of the mss stuff | ||
21 | */ | ||
22 | |||
23 | #include <linux/init.h> | ||
24 | #include <linux/module.h> | ||
25 | #include <linux/spinlock.h> | ||
26 | |||
27 | #undef SB_OK | ||
28 | |||
29 | #include "sound_config.h" | ||
30 | |||
31 | #include "ad1848.h" | ||
32 | #include "mpu401.h" | ||
33 | |||
34 | #ifdef SB_OK | ||
35 | #include "sb.h" | ||
36 | static int sb_initialized; | ||
37 | #endif | ||
38 | |||
39 | static DEFINE_SPINLOCK(lock); | ||
40 | |||
41 | static unsigned char opl3sa_read(int addr) | ||
42 | { | ||
43 | unsigned long flags; | ||
44 | unsigned char tmp; | ||
45 | |||
46 | spin_lock_irqsave(&lock,flags); | ||
47 | outb((0x1d), 0xf86); /* password */ | ||
48 | outb(((unsigned char) addr), 0xf86); /* address */ | ||
49 | tmp = inb(0xf87); /* data */ | ||
50 | spin_unlock_irqrestore(&lock,flags); | ||
51 | |||
52 | return tmp; | ||
53 | } | ||
54 | |||
55 | static void opl3sa_write(int addr, int data) | ||
56 | { | ||
57 | unsigned long flags; | ||
58 | |||
59 | spin_lock_irqsave(&lock,flags); | ||
60 | outb((0x1d), 0xf86); /* password */ | ||
61 | outb(((unsigned char) addr), 0xf86); /* address */ | ||
62 | outb(((unsigned char) data), 0xf87); /* data */ | ||
63 | spin_unlock_irqrestore(&lock,flags); | ||
64 | } | ||
65 | |||
66 | static int __init opl3sa_detect(void) | ||
67 | { | ||
68 | int tmp; | ||
69 | |||
70 | if (((tmp = opl3sa_read(0x01)) & 0xc4) != 0x04) | ||
71 | { | ||
72 | DDB(printk("OPL3-SA detect error 1 (%x)\n", opl3sa_read(0x01))); | ||
73 | /* return 0; */ | ||
74 | } | ||
75 | |||
76 | /* | ||
77 | * Check that the password feature has any effect | ||
78 | */ | ||
79 | |||
80 | if (inb(0xf87) == tmp) | ||
81 | { | ||
82 | DDB(printk("OPL3-SA detect failed 2 (%x/%x)\n", tmp, inb(0xf87))); | ||
83 | return 0; | ||
84 | } | ||
85 | tmp = (opl3sa_read(0x04) & 0xe0) >> 5; | ||
86 | |||
87 | if (tmp != 0 && tmp != 1) | ||
88 | { | ||
89 | DDB(printk("OPL3-SA detect failed 3 (%d)\n", tmp)); | ||
90 | return 0; | ||
91 | } | ||
92 | DDB(printk("OPL3-SA mode %x detected\n", tmp)); | ||
93 | |||
94 | opl3sa_write(0x01, 0x00); /* Disable MSS */ | ||
95 | opl3sa_write(0x02, 0x00); /* Disable SB */ | ||
96 | opl3sa_write(0x03, 0x00); /* Disable MPU */ | ||
97 | |||
98 | return 1; | ||
99 | } | ||
100 | |||
101 | /* | ||
102 | * Probe and attach routines for the Windows Sound System mode of | ||
103 | * OPL3-SA | ||
104 | */ | ||
105 | |||
106 | static int __init probe_opl3sa_wss(struct address_info *hw_config, struct resource *ports) | ||
107 | { | ||
108 | unsigned char tmp = 0x24; /* WSS enable */ | ||
109 | |||
110 | /* | ||
111 | * Check if the IO port returns valid signature. The original MS Sound | ||
112 | * system returns 0x04 while some cards (OPL3-SA for example) | ||
113 | * return 0x00. | ||
114 | */ | ||
115 | |||
116 | if (!opl3sa_detect()) | ||
117 | { | ||
118 | printk(KERN_ERR "OSS: OPL3-SA chip not found\n"); | ||
119 | return 0; | ||
120 | } | ||
121 | |||
122 | switch (hw_config->io_base) | ||
123 | { | ||
124 | case 0x530: | ||
125 | tmp |= 0x00; | ||
126 | break; | ||
127 | case 0xe80: | ||
128 | tmp |= 0x08; | ||
129 | break; | ||
130 | case 0xf40: | ||
131 | tmp |= 0x10; | ||
132 | break; | ||
133 | case 0x604: | ||
134 | tmp |= 0x18; | ||
135 | break; | ||
136 | default: | ||
137 | printk(KERN_ERR "OSS: Unsupported OPL3-SA/WSS base %x\n", hw_config->io_base); | ||
138 | return 0; | ||
139 | } | ||
140 | |||
141 | opl3sa_write(0x01, tmp); /* WSS setup register */ | ||
142 | |||
143 | return probe_ms_sound(hw_config, ports); | ||
144 | } | ||
145 | |||
146 | static void __init attach_opl3sa_wss(struct address_info *hw_config, struct resource *ports) | ||
147 | { | ||
148 | int nm = num_mixers; | ||
149 | |||
150 | /* FIXME */ | ||
151 | attach_ms_sound(hw_config, ports, THIS_MODULE); | ||
152 | if (num_mixers > nm) /* A mixer was installed */ | ||
153 | { | ||
154 | AD1848_REROUTE(SOUND_MIXER_LINE1, SOUND_MIXER_CD); | ||
155 | AD1848_REROUTE(SOUND_MIXER_LINE2, SOUND_MIXER_SYNTH); | ||
156 | AD1848_REROUTE(SOUND_MIXER_LINE3, SOUND_MIXER_LINE); | ||
157 | } | ||
158 | } | ||
159 | |||
160 | |||
161 | static int __init probe_opl3sa_mpu(struct address_info *hw_config) | ||
162 | { | ||
163 | unsigned char conf; | ||
164 | static signed char irq_bits[] = { | ||
165 | -1, -1, -1, -1, -1, 1, -1, 2, -1, 3, 4 | ||
166 | }; | ||
167 | |||
168 | if (hw_config->irq > 10) | ||
169 | { | ||
170 | printk(KERN_ERR "OPL3-SA: Bad MPU IRQ %d\n", hw_config->irq); | ||
171 | return 0; | ||
172 | } | ||
173 | if (irq_bits[hw_config->irq] == -1) | ||
174 | { | ||
175 | printk(KERN_ERR "OPL3-SA: Bad MPU IRQ %d\n", hw_config->irq); | ||
176 | return 0; | ||
177 | } | ||
178 | switch (hw_config->io_base) | ||
179 | { | ||
180 | case 0x330: | ||
181 | conf = 0x00; | ||
182 | break; | ||
183 | case 0x332: | ||
184 | conf = 0x20; | ||
185 | break; | ||
186 | case 0x334: | ||
187 | conf = 0x40; | ||
188 | break; | ||
189 | case 0x300: | ||
190 | conf = 0x60; | ||
191 | break; | ||
192 | default: | ||
193 | return 0; /* Invalid port */ | ||
194 | } | ||
195 | |||
196 | conf |= 0x83; /* MPU & OPL3 (synth) & game port enable */ | ||
197 | conf |= irq_bits[hw_config->irq] << 2; | ||
198 | |||
199 | opl3sa_write(0x03, conf); | ||
200 | |||
201 | hw_config->name = "OPL3-SA (MPU401)"; | ||
202 | |||
203 | return probe_uart401(hw_config, THIS_MODULE); | ||
204 | } | ||
205 | |||
206 | static void __exit unload_opl3sa_wss(struct address_info *hw_config) | ||
207 | { | ||
208 | int dma2 = hw_config->dma2; | ||
209 | |||
210 | if (dma2 == -1) | ||
211 | dma2 = hw_config->dma; | ||
212 | |||
213 | release_region(0xf86, 2); | ||
214 | release_region(hw_config->io_base, 4); | ||
215 | |||
216 | ad1848_unload(hw_config->io_base + 4, | ||
217 | hw_config->irq, | ||
218 | hw_config->dma, | ||
219 | dma2, | ||
220 | 0); | ||
221 | sound_unload_audiodev(hw_config->slots[0]); | ||
222 | } | ||
223 | |||
224 | static inline void __exit unload_opl3sa_mpu(struct address_info *hw_config) | ||
225 | { | ||
226 | unload_uart401(hw_config); | ||
227 | } | ||
228 | |||
229 | #ifdef SB_OK | ||
230 | static inline void __exit unload_opl3sa_sb(struct address_info *hw_config) | ||
231 | { | ||
232 | sb_dsp_unload(hw_config); | ||
233 | } | ||
234 | #endif | ||
235 | |||
236 | static int found_mpu; | ||
237 | |||
238 | static struct address_info cfg; | ||
239 | static struct address_info cfg_mpu; | ||
240 | |||
241 | static int __initdata io = -1; | ||
242 | static int __initdata irq = -1; | ||
243 | static int __initdata dma = -1; | ||
244 | static int __initdata dma2 = -1; | ||
245 | static int __initdata mpu_io = -1; | ||
246 | static int __initdata mpu_irq = -1; | ||
247 | |||
248 | module_param(io, int, 0); | ||
249 | module_param(irq, int, 0); | ||
250 | module_param(dma, int, 0); | ||
251 | module_param(dma2, int, 0); | ||
252 | module_param(mpu_io, int, 0); | ||
253 | module_param(mpu_irq, int, 0); | ||
254 | |||
255 | static int __init init_opl3sa(void) | ||
256 | { | ||
257 | struct resource *ports; | ||
258 | if (io == -1 || irq == -1 || dma == -1) { | ||
259 | printk(KERN_ERR "opl3sa: dma, irq and io must be set.\n"); | ||
260 | return -EINVAL; | ||
261 | } | ||
262 | |||
263 | cfg.io_base = io; | ||
264 | cfg.irq = irq; | ||
265 | cfg.dma = dma; | ||
266 | cfg.dma2 = dma2; | ||
267 | |||
268 | cfg_mpu.io_base = mpu_io; | ||
269 | cfg_mpu.irq = mpu_irq; | ||
270 | |||
271 | ports = request_region(io + 4, 4, "ad1848"); | ||
272 | if (!ports) | ||
273 | return -EBUSY; | ||
274 | |||
275 | if (!request_region(0xf86, 2, "OPL3-SA"))/* Control port is busy */ { | ||
276 | release_region(io + 4, 4); | ||
277 | return 0; | ||
278 | } | ||
279 | |||
280 | if (!request_region(io, 4, "WSS config")) { | ||
281 | release_region(0x86, 2); | ||
282 | release_region(io + 4, 4); | ||
283 | return 0; | ||
284 | } | ||
285 | |||
286 | if (probe_opl3sa_wss(&cfg, ports) == 0) { | ||
287 | release_region(0xf86, 2); | ||
288 | release_region(io, 4); | ||
289 | release_region(io + 4, 4); | ||
290 | return -ENODEV; | ||
291 | } | ||
292 | |||
293 | found_mpu=probe_opl3sa_mpu(&cfg_mpu); | ||
294 | |||
295 | attach_opl3sa_wss(&cfg, ports); | ||
296 | return 0; | ||
297 | } | ||
298 | |||
299 | static void __exit cleanup_opl3sa(void) | ||
300 | { | ||
301 | if(found_mpu) | ||
302 | unload_opl3sa_mpu(&cfg_mpu); | ||
303 | unload_opl3sa_wss(&cfg); | ||
304 | } | ||
305 | |||
306 | module_init(init_opl3sa); | ||
307 | module_exit(cleanup_opl3sa); | ||
308 | |||
309 | #ifndef MODULE | ||
310 | static int __init setup_opl3sa(char *str) | ||
311 | { | ||
312 | /* io, irq, dma, dma2, mpu_io, mpu_irq */ | ||
313 | int ints[7]; | ||
314 | |||
315 | str = get_options(str, ARRAY_SIZE(ints), ints); | ||
316 | |||
317 | io = ints[1]; | ||
318 | irq = ints[2]; | ||
319 | dma = ints[3]; | ||
320 | dma2 = ints[4]; | ||
321 | mpu_io = ints[5]; | ||
322 | mpu_irq = ints[6]; | ||
323 | |||
324 | return 1; | ||
325 | } | ||
326 | |||
327 | __setup("opl3sa=", setup_opl3sa); | ||
328 | #endif | ||
329 | MODULE_LICENSE("GPL"); | ||