Commit | Line | Data |
---|---|---|
1da177e4 LT |
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); | |
d390493b | 202 | MODULE_PARM_DESC(irq, "Set MSS (audio) IRQ (5, 7, 9, 10, 11, 12)"); |
1da177e4 LT |
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 |