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