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/opl3sa2.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/opl3sa2.c')
-rw-r--r-- | sound/oss/opl3sa2.c | 1129 |
1 files changed, 1129 insertions, 0 deletions
diff --git a/sound/oss/opl3sa2.c b/sound/oss/opl3sa2.c new file mode 100644 index 000000000000..7b4996e71576 --- /dev/null +++ b/sound/oss/opl3sa2.c | |||
@@ -0,0 +1,1129 @@ | |||
1 | /* | ||
2 | * sound/opl3sa2.c | ||
3 | * | ||
4 | * A low level driver for Yamaha OPL3-SA2 and SA3 cards. | ||
5 | * NOTE: All traces of the name OPL3-SAx have now (December 2000) been | ||
6 | * removed from the driver code, as an email exchange with Yamaha | ||
7 | * provided the information that the YMF-719 is indeed just a | ||
8 | * re-badged 715. | ||
9 | * | ||
10 | * Copyright 1998-2001 Scott Murray <scott@spiteful.org> | ||
11 | * | ||
12 | * Originally based on the CS4232 driver (in cs4232.c) by Hannu Savolainen | ||
13 | * and others. Now incorporates code/ideas from pss.c, also by Hannu | ||
14 | * Savolainen. Both of those files are distributed with the following | ||
15 | * license: | ||
16 | * | ||
17 | * "Copyright (C) by Hannu Savolainen 1993-1997 | ||
18 | * | ||
19 | * OSS/Free for Linux is distributed under the GNU GENERAL PUBLIC LICENSE (GPL) | ||
20 | * Version 2 (June 1991). See the "COPYING" file distributed with this software | ||
21 | * for more info." | ||
22 | * | ||
23 | * As such, in accordance with the above license, this file, opl3sa2.c, is | ||
24 | * distributed under the GNU GENERAL PUBLIC LICENSE (GPL) Version 2 (June 1991). | ||
25 | * See the "COPYING" file distributed with this software for more information. | ||
26 | * | ||
27 | * Change History | ||
28 | * -------------- | ||
29 | * Scott Murray Original driver (Jun 14, 1998) | ||
30 | * Paul J.Y. Lahaie Changed probing / attach code order | ||
31 | * Scott Murray Added mixer support (Dec 03, 1998) | ||
32 | * Scott Murray Changed detection code to be more forgiving, | ||
33 | * added force option as last resort, | ||
34 | * fixed ioctl return values. (Dec 30, 1998) | ||
35 | * Scott Murray Simpler detection code should work all the time now | ||
36 | * (with thanks to Ben Hutchings for the heuristic), | ||
37 | * removed now unnecessary force option. (Jan 5, 1999) | ||
38 | * Christoph Hellwig Adapted to module_init/module_exit (Mar 4, 2000) | ||
39 | * Scott Murray Reworked SA2 versus SA3 mixer code, updated chipset | ||
40 | * version detection code (again!). (Dec 5, 2000) | ||
41 | * Scott Murray Adjusted master volume mixer scaling. (Dec 6, 2000) | ||
42 | * Scott Murray Based on a patch by Joel Yliluoma (aka Bisqwit), | ||
43 | * integrated wide mixer and adjusted mic, bass, treble | ||
44 | * scaling. (Dec 6, 2000) | ||
45 | * Scott Murray Based on a patch by Peter Englmaier, integrated | ||
46 | * ymode and loopback options. (Dec 6, 2000) | ||
47 | * Scott Murray Inspired by a patch by Peter Englmaier, and based on | ||
48 | * what ALSA does, added initialization code for the | ||
49 | * default DMA and IRQ settings. (Dec 6, 2000) | ||
50 | * Scott Murray Added some more checks to the card detection code, | ||
51 | * based on what ALSA does. (Dec 12, 2000) | ||
52 | * Scott Murray Inspired by similar patches from John Fremlin, | ||
53 | * Jim Radford, Mike Rolig, and Ingmar Steen, added 2.4 | ||
54 | * ISA PnP API support, mainly based on bits from | ||
55 | * sb_card.c and awe_wave.c. (Dec 12, 2000) | ||
56 | * Scott Murray Some small cleanups to the init code output. | ||
57 | * (Jan 7, 2001) | ||
58 | * Zwane Mwaikambo Added PM support. (Dec 4 2001) | ||
59 | * | ||
60 | * Adam Belay Converted driver to new PnP Layer (Oct 12, 2002) | ||
61 | * Zwane Mwaikambo Code, data structure cleanups. (Feb 15 2002) | ||
62 | * Zwane Mwaikambo Free resources during auxiliary device probe | ||
63 | * failures (Apr 29 2002) | ||
64 | * | ||
65 | */ | ||
66 | |||
67 | #include <linux/config.h> | ||
68 | #include <linux/pnp.h> | ||
69 | #include <linux/init.h> | ||
70 | #include <linux/module.h> | ||
71 | #include <linux/delay.h> | ||
72 | #include <linux/pm.h> | ||
73 | #include "sound_config.h" | ||
74 | |||
75 | #include "ad1848.h" | ||
76 | #include "mpu401.h" | ||
77 | |||
78 | #define OPL3SA2_MODULE_NAME "opl3sa2" | ||
79 | #define PFX OPL3SA2_MODULE_NAME ": " | ||
80 | |||
81 | /* Useful control port indexes: */ | ||
82 | #define OPL3SA2_PM 0x01 | ||
83 | #define OPL3SA2_SYS_CTRL 0x02 | ||
84 | #define OPL3SA2_IRQ_CONFIG 0x03 | ||
85 | #define OPL3SA2_DMA_CONFIG 0x06 | ||
86 | #define OPL3SA2_MASTER_LEFT 0x07 | ||
87 | #define OPL3SA2_MASTER_RIGHT 0x08 | ||
88 | #define OPL3SA2_MIC 0x09 | ||
89 | #define OPL3SA2_MISC 0x0A | ||
90 | |||
91 | #define OPL3SA3_WIDE 0x14 | ||
92 | #define OPL3SA3_BASS 0x15 | ||
93 | #define OPL3SA3_TREBLE 0x16 | ||
94 | |||
95 | /* Useful constants: */ | ||
96 | #define DEFAULT_VOLUME 50 | ||
97 | #define DEFAULT_MIC 50 | ||
98 | #define DEFAULT_TIMBRE 0 | ||
99 | |||
100 | /* Power saving modes */ | ||
101 | #define OPL3SA2_PM_MODE0 0x00 | ||
102 | #define OPL3SA2_PM_MODE1 0x04 /* PSV */ | ||
103 | #define OPL3SA2_PM_MODE2 0x05 /* PSV | PDX */ | ||
104 | #define OPL3SA2_PM_MODE3 0x27 /* ADOWN | PSV | PDN | PDX */ | ||
105 | |||
106 | |||
107 | /* For checking against what the card returns: */ | ||
108 | #define VERSION_UNKNOWN 0 | ||
109 | #define VERSION_YMF711 1 | ||
110 | #define VERSION_YMF715 2 | ||
111 | #define VERSION_YMF715B 3 | ||
112 | #define VERSION_YMF715E 4 | ||
113 | /* also assuming that anything > 4 but <= 7 is a 715E */ | ||
114 | |||
115 | /* Chipset type constants for use below */ | ||
116 | #define CHIPSET_UNKNOWN -1 | ||
117 | #define CHIPSET_OPL3SA2 0 | ||
118 | #define CHIPSET_OPL3SA3 1 | ||
119 | static const char *CHIPSET_TABLE[] = {"OPL3-SA2", "OPL3-SA3"}; | ||
120 | |||
121 | #ifdef CONFIG_PNP | ||
122 | #define OPL3SA2_CARDS_MAX 4 | ||
123 | #else | ||
124 | #define OPL3SA2_CARDS_MAX 1 | ||
125 | #endif | ||
126 | |||
127 | /* This should be pretty obvious */ | ||
128 | static int opl3sa2_cards_num; | ||
129 | |||
130 | typedef struct { | ||
131 | /* device resources */ | ||
132 | unsigned short cfg_port; | ||
133 | struct address_info cfg; | ||
134 | struct address_info cfg_mss; | ||
135 | struct address_info cfg_mpu; | ||
136 | #ifdef CONFIG_PNP | ||
137 | /* PnP Stuff */ | ||
138 | struct pnp_dev* pdev; | ||
139 | int activated; /* Whether said devices have been activated */ | ||
140 | #endif | ||
141 | #ifdef CONFIG_PM | ||
142 | unsigned int in_suspend; | ||
143 | struct pm_dev *pmdev; | ||
144 | #endif | ||
145 | unsigned int card; | ||
146 | int chipset; /* What's my version(s)? */ | ||
147 | char *chipset_name; | ||
148 | |||
149 | /* mixer data */ | ||
150 | int mixer; | ||
151 | unsigned int volume_l; | ||
152 | unsigned int volume_r; | ||
153 | unsigned int mic; | ||
154 | unsigned int bass_l; | ||
155 | unsigned int bass_r; | ||
156 | unsigned int treble_l; | ||
157 | unsigned int treble_r; | ||
158 | unsigned int wide_l; | ||
159 | unsigned int wide_r; | ||
160 | } opl3sa2_state_t; | ||
161 | static opl3sa2_state_t opl3sa2_state[OPL3SA2_CARDS_MAX]; | ||
162 | |||
163 | |||
164 | |||
165 | /* Our parameters */ | ||
166 | static int __initdata io = -1; | ||
167 | static int __initdata mss_io = -1; | ||
168 | static int __initdata mpu_io = -1; | ||
169 | static int __initdata irq = -1; | ||
170 | static int __initdata dma = -1; | ||
171 | static int __initdata dma2 = -1; | ||
172 | static int __initdata ymode = -1; | ||
173 | static int __initdata loopback = -1; | ||
174 | |||
175 | #ifdef CONFIG_PNP | ||
176 | /* PnP specific parameters */ | ||
177 | static int __initdata isapnp = 1; | ||
178 | static int __initdata multiple = 1; | ||
179 | |||
180 | /* Whether said devices have been activated */ | ||
181 | static int opl3sa2_activated[OPL3SA2_CARDS_MAX]; | ||
182 | #else | ||
183 | static int __initdata isapnp; /* = 0 */ | ||
184 | static int __initdata multiple; /* = 0 */ | ||
185 | #endif | ||
186 | |||
187 | MODULE_DESCRIPTION("Module for OPL3-SA2 and SA3 sound cards (uses AD1848 MSS driver)."); | ||
188 | MODULE_AUTHOR("Scott Murray <scott@spiteful.org>"); | ||
189 | MODULE_LICENSE("GPL"); | ||
190 | |||
191 | |||
192 | module_param(io, int, 0); | ||
193 | MODULE_PARM_DESC(io, "Set I/O base of OPL3-SA2 or SA3 card (usually 0x370. Address must be even and must be from 0x100 to 0xFFE)"); | ||
194 | |||
195 | module_param(mss_io, int, 0); | ||
196 | MODULE_PARM_DESC(mss_io, "Set MSS (audio) I/O base (0x530, 0xE80, or other. Address must end in 0 or 4 and must be from 0x530 to 0xF48)"); | ||
197 | |||
198 | module_param(mpu_io, int, 0); | ||
199 | MODULE_PARM_DESC(mpu_io, "Set MIDI I/O base (0x330 or other. Address must be even and must be from 0x300 to 0x334)"); | ||
200 | |||
201 | module_param(irq, int, 0); | ||
202 | MODULE_PARM_DESC(mss_irq, "Set MSS (audio) IRQ (5, 7, 9, 10, 11, 12)"); | ||
203 | |||
204 | module_param(dma, int, 0); | ||
205 | MODULE_PARM_DESC(dma, "Set MSS (audio) first DMA channel (0, 1, 3)"); | ||
206 | |||
207 | module_param(dma2, int, 0); | ||
208 | MODULE_PARM_DESC(dma2, "Set MSS (audio) second DMA channel (0, 1, 3)"); | ||
209 | |||
210 | module_param(ymode, int, 0); | ||
211 | MODULE_PARM_DESC(ymode, "Set Yamaha 3D enhancement mode (0 = Desktop/Normal, 1 = Notebook PC (1), 2 = Notebook PC (2), 3 = Hi-Fi)"); | ||
212 | |||
213 | module_param(loopback, int, 0); | ||
214 | MODULE_PARM_DESC(loopback, "Set A/D input source. Useful for echo cancellation (0 = Mic Rch (default), 1 = Mono output loopback)"); | ||
215 | |||
216 | #ifdef CONFIG_PNP | ||
217 | module_param(isapnp, bool, 0); | ||
218 | MODULE_PARM_DESC(isapnp, "When set to 0, ISA PnP support will be disabled"); | ||
219 | |||
220 | module_param(multiple, bool, 0); | ||
221 | MODULE_PARM_DESC(multiple, "When set to 0, will not search for multiple cards"); | ||
222 | #endif | ||
223 | |||
224 | |||
225 | /* | ||
226 | * Standard read and write functions | ||
227 | */ | ||
228 | |||
229 | static inline void opl3sa2_write(unsigned short port, | ||
230 | unsigned char index, | ||
231 | unsigned char data) | ||
232 | { | ||
233 | outb_p(index, port); | ||
234 | outb(data, port + 1); | ||
235 | } | ||
236 | |||
237 | |||
238 | static inline void opl3sa2_read(unsigned short port, | ||
239 | unsigned char index, | ||
240 | unsigned char* data) | ||
241 | { | ||
242 | outb_p(index, port); | ||
243 | *data = inb(port + 1); | ||
244 | } | ||
245 | |||
246 | |||
247 | /* | ||
248 | * All of the mixer functions... | ||
249 | */ | ||
250 | |||
251 | static void opl3sa2_set_volume(opl3sa2_state_t* devc, int left, int right) | ||
252 | { | ||
253 | static unsigned char scale[101] = { | ||
254 | 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0e, 0x0e, 0x0e, | ||
255 | 0x0e, 0x0e, 0x0e, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0c, | ||
256 | 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0b, 0x0b, 0x0b, 0x0b, | ||
257 | 0x0b, 0x0b, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x09, 0x09, | ||
258 | 0x09, 0x09, 0x09, 0x09, 0x09, 0x08, 0x08, 0x08, 0x08, 0x08, | ||
259 | 0x08, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x06, 0x06, 0x06, | ||
260 | 0x06, 0x06, 0x06, 0x06, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, | ||
261 | 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x03, 0x03, 0x03, 0x03, | ||
262 | 0x03, 0x03, 0x03, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x01, | ||
263 | 0x01, 0x01, 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
264 | 0x00 | ||
265 | }; | ||
266 | unsigned char vol; | ||
267 | |||
268 | vol = scale[left]; | ||
269 | |||
270 | /* If level is zero, turn on mute */ | ||
271 | if(!left) | ||
272 | vol |= 0x80; | ||
273 | |||
274 | opl3sa2_write(devc->cfg_port, OPL3SA2_MASTER_LEFT, vol); | ||
275 | |||
276 | vol = scale[right]; | ||
277 | |||
278 | /* If level is zero, turn on mute */ | ||
279 | if(!right) | ||
280 | vol |= 0x80; | ||
281 | |||
282 | opl3sa2_write(devc->cfg_port, OPL3SA2_MASTER_RIGHT, vol); | ||
283 | } | ||
284 | |||
285 | |||
286 | static void opl3sa2_set_mic(opl3sa2_state_t* devc, int level) | ||
287 | { | ||
288 | unsigned char vol = 0x1F; | ||
289 | |||
290 | if((level >= 0) && (level <= 100)) | ||
291 | vol = 0x1F - (unsigned char) (32 * level / 101); | ||
292 | |||
293 | /* If level is zero, turn on mute */ | ||
294 | if(!level) | ||
295 | vol |= 0x80; | ||
296 | |||
297 | opl3sa2_write(devc->cfg_port, OPL3SA2_MIC, vol); | ||
298 | } | ||
299 | |||
300 | |||
301 | static void opl3sa3_set_bass(opl3sa2_state_t* devc, int left, int right) | ||
302 | { | ||
303 | unsigned char bass; | ||
304 | |||
305 | bass = left ? ((unsigned char) (8 * left / 101)) : 0; | ||
306 | bass |= (right ? ((unsigned char) (8 * right / 101)) : 0) << 4; | ||
307 | |||
308 | opl3sa2_write(devc->cfg_port, OPL3SA3_BASS, bass); | ||
309 | } | ||
310 | |||
311 | |||
312 | static void opl3sa3_set_treble(opl3sa2_state_t* devc, int left, int right) | ||
313 | { | ||
314 | unsigned char treble; | ||
315 | |||
316 | treble = left ? ((unsigned char) (8 * left / 101)) : 0; | ||
317 | treble |= (right ? ((unsigned char) (8 * right / 101)) : 0) << 4; | ||
318 | |||
319 | opl3sa2_write(devc->cfg_port, OPL3SA3_TREBLE, treble); | ||
320 | } | ||
321 | |||
322 | |||
323 | |||
324 | |||
325 | static void opl3sa2_mixer_reset(opl3sa2_state_t* devc) | ||
326 | { | ||
327 | if (devc) { | ||
328 | opl3sa2_set_volume(devc, DEFAULT_VOLUME, DEFAULT_VOLUME); | ||
329 | devc->volume_l = devc->volume_r = DEFAULT_VOLUME; | ||
330 | |||
331 | opl3sa2_set_mic(devc, DEFAULT_MIC); | ||
332 | devc->mic = DEFAULT_MIC; | ||
333 | |||
334 | if (devc->chipset == CHIPSET_OPL3SA3) { | ||
335 | opl3sa3_set_bass(devc, DEFAULT_TIMBRE, DEFAULT_TIMBRE); | ||
336 | devc->bass_l = devc->bass_r = DEFAULT_TIMBRE; | ||
337 | opl3sa3_set_treble(devc, DEFAULT_TIMBRE, DEFAULT_TIMBRE); | ||
338 | devc->treble_l = devc->treble_r = DEFAULT_TIMBRE; | ||
339 | } | ||
340 | } | ||
341 | } | ||
342 | |||
343 | /* Currently only used for power management */ | ||
344 | #ifdef CONFIG_PM | ||
345 | static void opl3sa2_mixer_restore(opl3sa2_state_t* devc) | ||
346 | { | ||
347 | if (devc) { | ||
348 | opl3sa2_set_volume(devc, devc->volume_l, devc->volume_r); | ||
349 | opl3sa2_set_mic(devc, devc->mic); | ||
350 | |||
351 | if (devc->chipset == CHIPSET_OPL3SA3) { | ||
352 | opl3sa3_set_bass(devc, devc->bass_l, devc->bass_r); | ||
353 | opl3sa3_set_treble(devc, devc->treble_l, devc->treble_r); | ||
354 | } | ||
355 | } | ||
356 | } | ||
357 | #endif | ||
358 | |||
359 | static inline void arg_to_vol_mono(unsigned int vol, int* value) | ||
360 | { | ||
361 | int left; | ||
362 | |||
363 | left = vol & 0x00ff; | ||
364 | if (left > 100) | ||
365 | left = 100; | ||
366 | *value = left; | ||
367 | } | ||
368 | |||
369 | |||
370 | static inline void arg_to_vol_stereo(unsigned int vol, int* aleft, int* aright) | ||
371 | { | ||
372 | arg_to_vol_mono(vol, aleft); | ||
373 | arg_to_vol_mono(vol >> 8, aright); | ||
374 | } | ||
375 | |||
376 | |||
377 | static inline int ret_vol_mono(int vol) | ||
378 | { | ||
379 | return ((vol << 8) | vol); | ||
380 | } | ||
381 | |||
382 | |||
383 | static inline int ret_vol_stereo(int left, int right) | ||
384 | { | ||
385 | return ((right << 8) | left); | ||
386 | } | ||
387 | |||
388 | |||
389 | static int opl3sa2_mixer_ioctl(int dev, unsigned int cmd, void __user *arg) | ||
390 | { | ||
391 | int retval, value, cmdf = cmd & 0xff; | ||
392 | int __user *p = (int __user *)arg; | ||
393 | |||
394 | opl3sa2_state_t* devc = &opl3sa2_state[dev]; | ||
395 | |||
396 | switch (cmdf) { | ||
397 | case SOUND_MIXER_VOLUME: | ||
398 | case SOUND_MIXER_MIC: | ||
399 | case SOUND_MIXER_DEVMASK: | ||
400 | case SOUND_MIXER_STEREODEVS: | ||
401 | case SOUND_MIXER_RECMASK: | ||
402 | case SOUND_MIXER_RECSRC: | ||
403 | case SOUND_MIXER_CAPS: | ||
404 | break; | ||
405 | |||
406 | default: | ||
407 | return -EINVAL; | ||
408 | } | ||
409 | |||
410 | if (((cmd >> 8) & 0xff) != 'M') | ||
411 | return -EINVAL; | ||
412 | |||
413 | retval = 0; | ||
414 | if (_SIOC_DIR (cmd) & _SIOC_WRITE) { | ||
415 | switch (cmdf) { | ||
416 | case SOUND_MIXER_VOLUME: | ||
417 | retval = get_user(value, (unsigned __user *) arg); | ||
418 | if (retval) | ||
419 | break; | ||
420 | arg_to_vol_stereo(value, &devc->volume_l, &devc->volume_r); | ||
421 | opl3sa2_set_volume(devc, devc->volume_l, devc->volume_r); | ||
422 | value = ret_vol_stereo(devc->volume_l, devc->volume_r); | ||
423 | retval = put_user(value, p); | ||
424 | break; | ||
425 | |||
426 | case SOUND_MIXER_MIC: | ||
427 | retval = get_user(value, (unsigned __user *) arg); | ||
428 | if (retval) | ||
429 | break; | ||
430 | arg_to_vol_mono(value, &devc->mic); | ||
431 | opl3sa2_set_mic(devc, devc->mic); | ||
432 | value = ret_vol_mono(devc->mic); | ||
433 | retval = put_user(value, p); | ||
434 | break; | ||
435 | |||
436 | default: | ||
437 | retval = -EINVAL; | ||
438 | } | ||
439 | } | ||
440 | else { | ||
441 | /* | ||
442 | * Return parameters | ||
443 | */ | ||
444 | switch (cmdf) { | ||
445 | case SOUND_MIXER_DEVMASK: | ||
446 | retval = put_user(SOUND_MASK_VOLUME | SOUND_MASK_MIC, p); | ||
447 | break; | ||
448 | |||
449 | case SOUND_MIXER_STEREODEVS: | ||
450 | retval = put_user(SOUND_MASK_VOLUME, p); | ||
451 | break; | ||
452 | |||
453 | case SOUND_MIXER_RECMASK: | ||
454 | /* No recording devices */ | ||
455 | retval = put_user(0, p); | ||
456 | break; | ||
457 | |||
458 | case SOUND_MIXER_CAPS: | ||
459 | retval = put_user(SOUND_CAP_EXCL_INPUT, p); | ||
460 | break; | ||
461 | |||
462 | case SOUND_MIXER_RECSRC: | ||
463 | /* No recording source */ | ||
464 | retval = put_user(0, p); | ||
465 | break; | ||
466 | |||
467 | case SOUND_MIXER_VOLUME: | ||
468 | value = ret_vol_stereo(devc->volume_l, devc->volume_r); | ||
469 | retval = put_user(value, p); | ||
470 | break; | ||
471 | |||
472 | case SOUND_MIXER_MIC: | ||
473 | value = ret_vol_mono(devc->mic); | ||
474 | put_user(value, p); | ||
475 | break; | ||
476 | |||
477 | default: | ||
478 | retval = -EINVAL; | ||
479 | } | ||
480 | } | ||
481 | return retval; | ||
482 | } | ||
483 | /* opl3sa2_mixer_ioctl end */ | ||
484 | |||
485 | |||
486 | static int opl3sa3_mixer_ioctl(int dev, unsigned int cmd, void __user * arg) | ||
487 | { | ||
488 | int value, retval, cmdf = cmd & 0xff; | ||
489 | |||
490 | opl3sa2_state_t* devc = &opl3sa2_state[dev]; | ||
491 | |||
492 | switch (cmdf) { | ||
493 | case SOUND_MIXER_BASS: | ||
494 | value = ret_vol_stereo(devc->bass_l, devc->bass_r); | ||
495 | retval = put_user(value, (int __user *) arg); | ||
496 | break; | ||
497 | |||
498 | case SOUND_MIXER_TREBLE: | ||
499 | value = ret_vol_stereo(devc->treble_l, devc->treble_r); | ||
500 | retval = put_user(value, (int __user *) arg); | ||
501 | break; | ||
502 | |||
503 | case SOUND_MIXER_DIGITAL1: | ||
504 | value = ret_vol_stereo(devc->wide_l, devc->wide_r); | ||
505 | retval = put_user(value, (int __user *) arg); | ||
506 | break; | ||
507 | |||
508 | default: | ||
509 | retval = -EINVAL; | ||
510 | } | ||
511 | return retval; | ||
512 | } | ||
513 | /* opl3sa3_mixer_ioctl end */ | ||
514 | |||
515 | |||
516 | static struct mixer_operations opl3sa2_mixer_operations = | ||
517 | { | ||
518 | .owner = THIS_MODULE, | ||
519 | .id = "OPL3-SA2", | ||
520 | .name = "Yamaha OPL3-SA2", | ||
521 | .ioctl = opl3sa2_mixer_ioctl | ||
522 | }; | ||
523 | |||
524 | static struct mixer_operations opl3sa3_mixer_operations = | ||
525 | { | ||
526 | .owner = THIS_MODULE, | ||
527 | .id = "OPL3-SA3", | ||
528 | .name = "Yamaha OPL3-SA3", | ||
529 | .ioctl = opl3sa3_mixer_ioctl | ||
530 | }; | ||
531 | |||
532 | /* End of mixer-related stuff */ | ||
533 | |||
534 | |||
535 | /* | ||
536 | * Component probe, attach, unload functions | ||
537 | */ | ||
538 | |||
539 | static inline void __exit unload_opl3sa2_mpu(struct address_info *hw_config) | ||
540 | { | ||
541 | unload_mpu401(hw_config); | ||
542 | } | ||
543 | |||
544 | |||
545 | static void __init attach_opl3sa2_mss(struct address_info* hw_config, struct resource *ports) | ||
546 | { | ||
547 | int initial_mixers; | ||
548 | |||
549 | initial_mixers = num_mixers; | ||
550 | attach_ms_sound(hw_config, ports, THIS_MODULE); /* Slot 0 */ | ||
551 | if (hw_config->slots[0] != -1) { | ||
552 | /* Did the MSS driver install? */ | ||
553 | if(num_mixers == (initial_mixers + 1)) { | ||
554 | /* The MSS mixer is installed, reroute mixers appropiately */ | ||
555 | AD1848_REROUTE(SOUND_MIXER_LINE1, SOUND_MIXER_CD); | ||
556 | AD1848_REROUTE(SOUND_MIXER_LINE2, SOUND_MIXER_SYNTH); | ||
557 | AD1848_REROUTE(SOUND_MIXER_LINE3, SOUND_MIXER_LINE); | ||
558 | } | ||
559 | else { | ||
560 | printk(KERN_ERR PFX "MSS mixer not installed?\n"); | ||
561 | } | ||
562 | } | ||
563 | } | ||
564 | |||
565 | |||
566 | static inline void __exit unload_opl3sa2_mss(struct address_info* hw_config) | ||
567 | { | ||
568 | unload_ms_sound(hw_config); | ||
569 | } | ||
570 | |||
571 | |||
572 | static int __init probe_opl3sa2(struct address_info* hw_config, int card) | ||
573 | { | ||
574 | unsigned char misc; | ||
575 | unsigned char tmp; | ||
576 | unsigned char version; | ||
577 | |||
578 | /* | ||
579 | * Try and allocate our I/O port range. | ||
580 | */ | ||
581 | if (!request_region(hw_config->io_base, 2, OPL3SA2_MODULE_NAME)) { | ||
582 | printk(KERN_ERR PFX "Control I/O port %#x not free\n", | ||
583 | hw_config->io_base); | ||
584 | goto out_nodev; | ||
585 | } | ||
586 | |||
587 | /* | ||
588 | * Check if writing to the read-only version bits of the miscellaneous | ||
589 | * register succeeds or not (it should not). | ||
590 | */ | ||
591 | opl3sa2_read(hw_config->io_base, OPL3SA2_MISC, &misc); | ||
592 | opl3sa2_write(hw_config->io_base, OPL3SA2_MISC, misc ^ 0x07); | ||
593 | opl3sa2_read(hw_config->io_base, OPL3SA2_MISC, &tmp); | ||
594 | if(tmp != misc) { | ||
595 | printk(KERN_ERR PFX "Control I/O port %#x is not a YMF7xx chipset!\n", | ||
596 | hw_config->io_base); | ||
597 | goto out_region; | ||
598 | } | ||
599 | |||
600 | /* | ||
601 | * Check if the MIC register is accessible. | ||
602 | */ | ||
603 | opl3sa2_read(hw_config->io_base, OPL3SA2_MIC, &tmp); | ||
604 | opl3sa2_write(hw_config->io_base, OPL3SA2_MIC, 0x8a); | ||
605 | opl3sa2_read(hw_config->io_base, OPL3SA2_MIC, &tmp); | ||
606 | if((tmp & 0x9f) != 0x8a) { | ||
607 | printk(KERN_ERR | ||
608 | PFX "Control I/O port %#x is not a YMF7xx chipset!\n", | ||
609 | hw_config->io_base); | ||
610 | goto out_region; | ||
611 | } | ||
612 | opl3sa2_write(hw_config->io_base, OPL3SA2_MIC, tmp); | ||
613 | |||
614 | /* | ||
615 | * Determine chipset type (SA2 or SA3) | ||
616 | * | ||
617 | * This is done by looking at the chipset version in the lower 3 bits | ||
618 | * of the miscellaneous register. | ||
619 | */ | ||
620 | version = misc & 0x07; | ||
621 | printk(KERN_DEBUG PFX "Chipset version = %#x\n", version); | ||
622 | switch (version) { | ||
623 | case 0: | ||
624 | opl3sa2_state[card].chipset = CHIPSET_UNKNOWN; | ||
625 | printk(KERN_ERR | ||
626 | PFX "Unknown Yamaha audio controller version\n"); | ||
627 | break; | ||
628 | |||
629 | case VERSION_YMF711: | ||
630 | opl3sa2_state[card].chipset = CHIPSET_OPL3SA2; | ||
631 | printk(KERN_INFO PFX "Found OPL3-SA2 (YMF711)\n"); | ||
632 | break; | ||
633 | |||
634 | case VERSION_YMF715: | ||
635 | opl3sa2_state[card].chipset = CHIPSET_OPL3SA3; | ||
636 | printk(KERN_INFO | ||
637 | PFX "Found OPL3-SA3 (YMF715 or YMF719)\n"); | ||
638 | break; | ||
639 | |||
640 | case VERSION_YMF715B: | ||
641 | opl3sa2_state[card].chipset = CHIPSET_OPL3SA3; | ||
642 | printk(KERN_INFO | ||
643 | PFX "Found OPL3-SA3 (YMF715B or YMF719B)\n"); | ||
644 | break; | ||
645 | |||
646 | case VERSION_YMF715E: | ||
647 | default: | ||
648 | opl3sa2_state[card].chipset = CHIPSET_OPL3SA3; | ||
649 | printk(KERN_INFO | ||
650 | PFX "Found OPL3-SA3 (YMF715E or YMF719E)\n"); | ||
651 | break; | ||
652 | } | ||
653 | |||
654 | if (opl3sa2_state[card].chipset != CHIPSET_UNKNOWN) { | ||
655 | /* Generate a pretty name */ | ||
656 | opl3sa2_state[card].chipset_name = (char *)CHIPSET_TABLE[opl3sa2_state[card].chipset]; | ||
657 | return 0; | ||
658 | } | ||
659 | |||
660 | out_region: | ||
661 | release_region(hw_config->io_base, 2); | ||
662 | out_nodev: | ||
663 | return -ENODEV; | ||
664 | } | ||
665 | |||
666 | |||
667 | static void __init attach_opl3sa2(struct address_info* hw_config, int card) | ||
668 | { | ||
669 | /* Initialize IRQ configuration to IRQ-B: -, IRQ-A: WSS+MPU+OPL3 */ | ||
670 | opl3sa2_write(hw_config->io_base, OPL3SA2_IRQ_CONFIG, 0x0d); | ||
671 | |||
672 | /* Initialize DMA configuration */ | ||
673 | if(hw_config->dma2 == hw_config->dma) { | ||
674 | /* Want DMA configuration DMA-B: -, DMA-A: WSS-P+WSS-R */ | ||
675 | opl3sa2_write(hw_config->io_base, OPL3SA2_DMA_CONFIG, 0x03); | ||
676 | } | ||
677 | else { | ||
678 | /* Want DMA configuration DMA-B: WSS-R, DMA-A: WSS-P */ | ||
679 | opl3sa2_write(hw_config->io_base, OPL3SA2_DMA_CONFIG, 0x21); | ||
680 | } | ||
681 | } | ||
682 | |||
683 | |||
684 | static void __init attach_opl3sa2_mixer(struct address_info *hw_config, int card) | ||
685 | { | ||
686 | struct mixer_operations* mixer_operations; | ||
687 | opl3sa2_state_t* devc = &opl3sa2_state[card]; | ||
688 | |||
689 | /* Install master mixer */ | ||
690 | if (devc->chipset == CHIPSET_OPL3SA3) { | ||
691 | mixer_operations = &opl3sa3_mixer_operations; | ||
692 | } | ||
693 | else { | ||
694 | mixer_operations = &opl3sa2_mixer_operations; | ||
695 | } | ||
696 | |||
697 | devc->cfg_port = hw_config->io_base; | ||
698 | devc->mixer = sound_install_mixer(MIXER_DRIVER_VERSION, | ||
699 | mixer_operations->name, | ||
700 | mixer_operations, | ||
701 | sizeof(struct mixer_operations), | ||
702 | devc); | ||
703 | if(devc->mixer < 0) { | ||
704 | printk(KERN_ERR PFX "Could not install %s master mixer\n", | ||
705 | mixer_operations->name); | ||
706 | } | ||
707 | else { | ||
708 | opl3sa2_mixer_reset(devc); | ||
709 | |||
710 | } | ||
711 | } | ||
712 | |||
713 | |||
714 | static void opl3sa2_clear_slots(struct address_info* hw_config) | ||
715 | { | ||
716 | int i; | ||
717 | |||
718 | for(i = 0; i < 6; i++) { | ||
719 | hw_config->slots[i] = -1; | ||
720 | } | ||
721 | } | ||
722 | |||
723 | |||
724 | static void __init opl3sa2_set_ymode(struct address_info* hw_config, int ymode) | ||
725 | { | ||
726 | /* | ||
727 | * Set the Yamaha 3D enhancement mode (aka Ymersion) if asked to and | ||
728 | * it's supported. | ||
729 | * | ||
730 | * 0: Desktop (aka normal) 5-12 cm speakers | ||
731 | * 1: Notebook PC mode 1 3 cm speakers | ||
732 | * 2: Notebook PC mode 2 1.5 cm speakers | ||
733 | * 3: Hi-fi 16-38 cm speakers | ||
734 | */ | ||
735 | if(ymode >= 0 && ymode <= 3) { | ||
736 | unsigned char sys_ctrl; | ||
737 | |||
738 | opl3sa2_read(hw_config->io_base, OPL3SA2_SYS_CTRL, &sys_ctrl); | ||
739 | sys_ctrl = (sys_ctrl & 0xcf) | ((ymode & 3) << 4); | ||
740 | opl3sa2_write(hw_config->io_base, OPL3SA2_SYS_CTRL, sys_ctrl); | ||
741 | } | ||
742 | else { | ||
743 | printk(KERN_ERR PFX "not setting ymode, it must be one of 0,1,2,3\n"); | ||
744 | } | ||
745 | } | ||
746 | |||
747 | |||
748 | static void __init opl3sa2_set_loopback(struct address_info* hw_config, int loopback) | ||
749 | { | ||
750 | if(loopback >= 0 && loopback <= 1) { | ||
751 | unsigned char misc; | ||
752 | |||
753 | opl3sa2_read(hw_config->io_base, OPL3SA2_MISC, &misc); | ||
754 | misc = (misc & 0xef) | ((loopback & 1) << 4); | ||
755 | opl3sa2_write(hw_config->io_base, OPL3SA2_MISC, misc); | ||
756 | } | ||
757 | else { | ||
758 | printk(KERN_ERR PFX "not setting loopback, it must be either 0 or 1\n"); | ||
759 | } | ||
760 | } | ||
761 | |||
762 | |||
763 | static void __exit unload_opl3sa2(struct address_info* hw_config, int card) | ||
764 | { | ||
765 | /* Release control ports */ | ||
766 | release_region(hw_config->io_base, 2); | ||
767 | |||
768 | /* Unload mixer */ | ||
769 | if(opl3sa2_state[card].mixer >= 0) | ||
770 | sound_unload_mixerdev(opl3sa2_state[card].mixer); | ||
771 | |||
772 | } | ||
773 | |||
774 | #ifdef CONFIG_PNP | ||
775 | static struct pnp_device_id pnp_opl3sa2_list[] = { | ||
776 | {.id = "YMH0021", .driver_data = 0}, | ||
777 | {.id = ""} | ||
778 | }; | ||
779 | |||
780 | MODULE_DEVICE_TABLE(pnp, pnp_opl3sa2_list); | ||
781 | |||
782 | static int opl3sa2_pnp_probe(struct pnp_dev *dev, const struct pnp_device_id *dev_id) | ||
783 | { | ||
784 | int card = opl3sa2_cards_num; | ||
785 | |||
786 | /* we don't actually want to return an error as the user may have specified | ||
787 | * no multiple card search | ||
788 | */ | ||
789 | |||
790 | if (opl3sa2_cards_num == OPL3SA2_CARDS_MAX) | ||
791 | return 0; | ||
792 | opl3sa2_activated[card] = 1; | ||
793 | |||
794 | /* Our own config: */ | ||
795 | opl3sa2_state[card].cfg.io_base = pnp_port_start(dev, 4); | ||
796 | opl3sa2_state[card].cfg.irq = pnp_irq(dev, 0); | ||
797 | opl3sa2_state[card].cfg.dma = pnp_dma(dev, 0); | ||
798 | opl3sa2_state[card].cfg.dma2 = pnp_dma(dev, 1); | ||
799 | |||
800 | /* The MSS config: */ | ||
801 | opl3sa2_state[card].cfg_mss.io_base = pnp_port_start(dev, 1); | ||
802 | opl3sa2_state[card].cfg_mss.irq = pnp_irq(dev, 0); | ||
803 | opl3sa2_state[card].cfg_mss.dma = pnp_dma(dev, 0); | ||
804 | opl3sa2_state[card].cfg_mss.dma2 = pnp_dma(dev, 1); | ||
805 | opl3sa2_state[card].cfg_mss.card_subtype = 1; /* No IRQ or DMA setup */ | ||
806 | |||
807 | opl3sa2_state[card].cfg_mpu.io_base = pnp_port_start(dev, 3); | ||
808 | opl3sa2_state[card].cfg_mpu.irq = pnp_irq(dev, 0); | ||
809 | opl3sa2_state[card].cfg_mpu.dma = -1; | ||
810 | opl3sa2_state[card].cfg_mpu.dma2 = -1; | ||
811 | opl3sa2_state[card].cfg_mpu.always_detect = 1; /* It's there, so use shared IRQs */ | ||
812 | |||
813 | /* Call me paranoid: */ | ||
814 | opl3sa2_clear_slots(&opl3sa2_state[card].cfg); | ||
815 | opl3sa2_clear_slots(&opl3sa2_state[card].cfg_mss); | ||
816 | opl3sa2_clear_slots(&opl3sa2_state[card].cfg_mpu); | ||
817 | |||
818 | opl3sa2_state[card].pdev = dev; | ||
819 | opl3sa2_cards_num++; | ||
820 | |||
821 | return 0; | ||
822 | } | ||
823 | |||
824 | static struct pnp_driver opl3sa2_driver = { | ||
825 | .name = "opl3sa2", | ||
826 | .id_table = pnp_opl3sa2_list, | ||
827 | .probe = opl3sa2_pnp_probe, | ||
828 | }; | ||
829 | |||
830 | #endif /* CONFIG_PNP */ | ||
831 | |||
832 | /* End of component functions */ | ||
833 | |||
834 | #ifdef CONFIG_PM | ||
835 | static DEFINE_SPINLOCK(opl3sa2_lock); | ||
836 | |||
837 | /* Power Management support functions */ | ||
838 | static int opl3sa2_suspend(struct pm_dev *pdev, unsigned int pm_mode) | ||
839 | { | ||
840 | unsigned long flags; | ||
841 | opl3sa2_state_t *p; | ||
842 | |||
843 | if (!pdev) | ||
844 | return -EINVAL; | ||
845 | |||
846 | spin_lock_irqsave(&opl3sa2_lock,flags); | ||
847 | |||
848 | p = (opl3sa2_state_t *) pdev->data; | ||
849 | switch (pm_mode) { | ||
850 | case 1: | ||
851 | pm_mode = OPL3SA2_PM_MODE1; | ||
852 | break; | ||
853 | case 2: | ||
854 | pm_mode = OPL3SA2_PM_MODE2; | ||
855 | break; | ||
856 | case 3: | ||
857 | pm_mode = OPL3SA2_PM_MODE3; | ||
858 | break; | ||
859 | default: | ||
860 | /* we don't know howto handle this... */ | ||
861 | spin_unlock_irqrestore(&opl3sa2_lock, flags); | ||
862 | return -EBUSY; | ||
863 | } | ||
864 | |||
865 | p->in_suspend = 1; | ||
866 | |||
867 | /* its supposed to automute before suspending, so we won't bother */ | ||
868 | opl3sa2_write(p->cfg_port, OPL3SA2_PM, pm_mode); | ||
869 | /* wait a while for the clock oscillator to stabilise */ | ||
870 | mdelay(10); | ||
871 | |||
872 | spin_unlock_irqrestore(&opl3sa2_lock,flags); | ||
873 | return 0; | ||
874 | } | ||
875 | |||
876 | static int opl3sa2_resume(struct pm_dev *pdev) | ||
877 | { | ||
878 | unsigned long flags; | ||
879 | opl3sa2_state_t *p; | ||
880 | |||
881 | if (!pdev) | ||
882 | return -EINVAL; | ||
883 | |||
884 | p = (opl3sa2_state_t *) pdev->data; | ||
885 | spin_lock_irqsave(&opl3sa2_lock,flags); | ||
886 | |||
887 | /* I don't think this is necessary */ | ||
888 | opl3sa2_write(p->cfg_port, OPL3SA2_PM, OPL3SA2_PM_MODE0); | ||
889 | opl3sa2_mixer_restore(p); | ||
890 | p->in_suspend = 0; | ||
891 | |||
892 | spin_unlock_irqrestore(&opl3sa2_lock,flags); | ||
893 | return 0; | ||
894 | } | ||
895 | |||
896 | static int opl3sa2_pm_callback(struct pm_dev *pdev, pm_request_t rqst, void *data) | ||
897 | { | ||
898 | unsigned long mode = (unsigned long)data; | ||
899 | |||
900 | switch (rqst) { | ||
901 | case PM_SUSPEND: | ||
902 | return opl3sa2_suspend(pdev, mode); | ||
903 | |||
904 | case PM_RESUME: | ||
905 | return opl3sa2_resume(pdev); | ||
906 | } | ||
907 | return 0; | ||
908 | } | ||
909 | #endif /* CONFIG_PM */ | ||
910 | |||
911 | /* | ||
912 | * Install OPL3-SA2 based card(s). | ||
913 | * | ||
914 | * Need to have ad1848 and mpu401 loaded ready. | ||
915 | */ | ||
916 | static int __init init_opl3sa2(void) | ||
917 | { | ||
918 | int card, max; | ||
919 | |||
920 | /* Sanitize isapnp and multiple settings */ | ||
921 | isapnp = isapnp != 0 ? 1 : 0; | ||
922 | multiple = multiple != 0 ? 1 : 0; | ||
923 | |||
924 | max = (multiple && isapnp) ? OPL3SA2_CARDS_MAX : 1; | ||
925 | |||
926 | #ifdef CONFIG_PNP | ||
927 | if (isapnp){ | ||
928 | pnp_register_driver(&opl3sa2_driver); | ||
929 | if(!opl3sa2_cards_num){ | ||
930 | printk(KERN_INFO PFX "No PnP cards found\n"); | ||
931 | isapnp = 0; | ||
932 | } | ||
933 | max = opl3sa2_cards_num; | ||
934 | } | ||
935 | #endif | ||
936 | |||
937 | for (card = 0; card < max; card++) { | ||
938 | /* If a user wants an I/O then assume they meant it */ | ||
939 | struct resource *ports; | ||
940 | int base; | ||
941 | |||
942 | if (!isapnp) { | ||
943 | if (io == -1 || irq == -1 || dma == -1 || | ||
944 | dma2 == -1 || mss_io == -1) { | ||
945 | printk(KERN_ERR | ||
946 | PFX "io, mss_io, irq, dma, and dma2 must be set\n"); | ||
947 | return -EINVAL; | ||
948 | } | ||
949 | opl3sa2_cards_num++; | ||
950 | |||
951 | /* | ||
952 | * Our own config: | ||
953 | * (NOTE: IRQ and DMA aren't used, so they're set to | ||
954 | * give pretty output from conf_printf. :) | ||
955 | */ | ||
956 | opl3sa2_state[card].cfg.io_base = io; | ||
957 | opl3sa2_state[card].cfg.irq = irq; | ||
958 | opl3sa2_state[card].cfg.dma = dma; | ||
959 | opl3sa2_state[card].cfg.dma2 = dma2; | ||
960 | |||
961 | /* The MSS config: */ | ||
962 | opl3sa2_state[card].cfg_mss.io_base = mss_io; | ||
963 | opl3sa2_state[card].cfg_mss.irq = irq; | ||
964 | opl3sa2_state[card].cfg_mss.dma = dma; | ||
965 | opl3sa2_state[card].cfg_mss.dma2 = dma2; | ||
966 | opl3sa2_state[card].cfg_mss.card_subtype = 1; /* No IRQ or DMA setup */ | ||
967 | |||
968 | opl3sa2_state[card].cfg_mpu.io_base = mpu_io; | ||
969 | opl3sa2_state[card].cfg_mpu.irq = irq; | ||
970 | opl3sa2_state[card].cfg_mpu.dma = -1; | ||
971 | opl3sa2_state[card].cfg_mpu.always_detect = 1; /* Use shared IRQs */ | ||
972 | |||
973 | /* Call me paranoid: */ | ||
974 | opl3sa2_clear_slots(&opl3sa2_state[card].cfg); | ||
975 | opl3sa2_clear_slots(&opl3sa2_state[card].cfg_mss); | ||
976 | opl3sa2_clear_slots(&opl3sa2_state[card].cfg_mpu); | ||
977 | } | ||
978 | |||
979 | /* FIXME: leak */ | ||
980 | if (probe_opl3sa2(&opl3sa2_state[card].cfg, card)) | ||
981 | return -ENODEV; | ||
982 | |||
983 | base = opl3sa2_state[card].cfg_mss.io_base; | ||
984 | |||
985 | if (!request_region(base, 4, "WSS config")) | ||
986 | goto failed; | ||
987 | |||
988 | ports = request_region(base + 4, 4, "ad1848"); | ||
989 | if (!ports) | ||
990 | goto failed2; | ||
991 | |||
992 | if (!probe_ms_sound(&opl3sa2_state[card].cfg_mss, ports)) { | ||
993 | /* | ||
994 | * If one or more cards are already registered, don't | ||
995 | * return an error but print a warning. Note, this | ||
996 | * should never really happen unless the hardware or | ||
997 | * ISA PnP screwed up. | ||
998 | */ | ||
999 | release_region(base + 4, 4); | ||
1000 | failed2: | ||
1001 | release_region(base, 4); | ||
1002 | failed: | ||
1003 | release_region(opl3sa2_state[card].cfg.io_base, 2); | ||
1004 | |||
1005 | if (opl3sa2_cards_num) { | ||
1006 | printk(KERN_WARNING | ||
1007 | PFX "There was a problem probing one " | ||
1008 | " of the ISA PNP cards, continuing\n"); | ||
1009 | opl3sa2_cards_num--; | ||
1010 | continue; | ||
1011 | } else | ||
1012 | return -ENODEV; | ||
1013 | } | ||
1014 | |||
1015 | attach_opl3sa2(&opl3sa2_state[card].cfg, card); | ||
1016 | conf_printf(opl3sa2_state[card].chipset_name, &opl3sa2_state[card].cfg); | ||
1017 | attach_opl3sa2_mixer(&opl3sa2_state[card].cfg, card); | ||
1018 | attach_opl3sa2_mss(&opl3sa2_state[card].cfg_mss, ports); | ||
1019 | |||
1020 | /* ewww =) */ | ||
1021 | opl3sa2_state[card].card = card; | ||
1022 | #ifdef CONFIG_PM | ||
1023 | /* register our power management capabilities */ | ||
1024 | opl3sa2_state[card].pmdev = pm_register(PM_ISA_DEV, card, opl3sa2_pm_callback); | ||
1025 | if (opl3sa2_state[card].pmdev) | ||
1026 | opl3sa2_state[card].pmdev->data = &opl3sa2_state[card]; | ||
1027 | #endif /* CONFIG_PM */ | ||
1028 | |||
1029 | /* | ||
1030 | * Set the Yamaha 3D enhancement mode (aka Ymersion) if asked to and | ||
1031 | * it's supported. | ||
1032 | */ | ||
1033 | if (ymode != -1) { | ||
1034 | if (opl3sa2_state[card].chipset == CHIPSET_OPL3SA2) { | ||
1035 | printk(KERN_ERR | ||
1036 | PFX "ymode not supported on OPL3-SA2\n"); | ||
1037 | } | ||
1038 | else { | ||
1039 | opl3sa2_set_ymode(&opl3sa2_state[card].cfg, ymode); | ||
1040 | } | ||
1041 | } | ||
1042 | |||
1043 | |||
1044 | /* Set A/D input to Mono loopback if asked to. */ | ||
1045 | if (loopback != -1) { | ||
1046 | opl3sa2_set_loopback(&opl3sa2_state[card].cfg, loopback); | ||
1047 | } | ||
1048 | |||
1049 | /* Attach MPU if we've been asked to do so, failure isn't fatal */ | ||
1050 | if (opl3sa2_state[card].cfg_mpu.io_base != -1) { | ||
1051 | int base = opl3sa2_state[card].cfg_mpu.io_base; | ||
1052 | struct resource *ports; | ||
1053 | ports = request_region(base, 2, "mpu401"); | ||
1054 | if (!ports) | ||
1055 | goto out; | ||
1056 | if (!probe_mpu401(&opl3sa2_state[card].cfg_mpu, ports)) { | ||
1057 | release_region(base, 2); | ||
1058 | goto out; | ||
1059 | } | ||
1060 | if (attach_mpu401(&opl3sa2_state[card].cfg_mpu, THIS_MODULE)) { | ||
1061 | printk(KERN_ERR PFX "failed to attach MPU401\n"); | ||
1062 | opl3sa2_state[card].cfg_mpu.slots[1] = -1; | ||
1063 | } | ||
1064 | } | ||
1065 | } | ||
1066 | |||
1067 | out: | ||
1068 | if (isapnp) { | ||
1069 | printk(KERN_NOTICE PFX "%d PnP card(s) found.\n", opl3sa2_cards_num); | ||
1070 | } | ||
1071 | |||
1072 | return 0; | ||
1073 | } | ||
1074 | |||
1075 | |||
1076 | /* | ||
1077 | * Uninstall OPL3-SA2 based card(s). | ||
1078 | */ | ||
1079 | static void __exit cleanup_opl3sa2(void) | ||
1080 | { | ||
1081 | int card; | ||
1082 | |||
1083 | for(card = 0; card < opl3sa2_cards_num; card++) { | ||
1084 | #ifdef CONFIG_PM | ||
1085 | if (opl3sa2_state[card].pmdev) | ||
1086 | pm_unregister(opl3sa2_state[card].pmdev); | ||
1087 | #endif | ||
1088 | if (opl3sa2_state[card].cfg_mpu.slots[1] != -1) { | ||
1089 | unload_opl3sa2_mpu(&opl3sa2_state[card].cfg_mpu); | ||
1090 | } | ||
1091 | unload_opl3sa2_mss(&opl3sa2_state[card].cfg_mss); | ||
1092 | unload_opl3sa2(&opl3sa2_state[card].cfg, card); | ||
1093 | #ifdef CONFIG_PNP | ||
1094 | pnp_unregister_driver(&opl3sa2_driver); | ||
1095 | #endif | ||
1096 | } | ||
1097 | } | ||
1098 | |||
1099 | module_init(init_opl3sa2); | ||
1100 | module_exit(cleanup_opl3sa2); | ||
1101 | |||
1102 | #ifndef MODULE | ||
1103 | static int __init setup_opl3sa2(char *str) | ||
1104 | { | ||
1105 | /* io, irq, dma, dma2,... */ | ||
1106 | #ifdef CONFIG_PNP | ||
1107 | int ints[11]; | ||
1108 | #else | ||
1109 | int ints[9]; | ||
1110 | #endif | ||
1111 | str = get_options(str, ARRAY_SIZE(ints), ints); | ||
1112 | |||
1113 | io = ints[1]; | ||
1114 | irq = ints[2]; | ||
1115 | dma = ints[3]; | ||
1116 | dma2 = ints[4]; | ||
1117 | mss_io = ints[5]; | ||
1118 | mpu_io = ints[6]; | ||
1119 | ymode = ints[7]; | ||
1120 | loopback = ints[8]; | ||
1121 | #ifdef CONFIG_PNP | ||
1122 | isapnp = ints[9]; | ||
1123 | multiple = ints[10]; | ||
1124 | #endif | ||
1125 | return 1; | ||
1126 | } | ||
1127 | |||
1128 | __setup("opl3sa2=", setup_opl3sa2); | ||
1129 | #endif | ||