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