2 * Routines for Gravis UltraSound soundcards
3 * Copyright (c) by Jaroslav Kysela <perex@suse.cz>
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
22 #include <sound/driver.h>
23 #include <linux/init.h>
24 #include <linux/interrupt.h>
25 #include <linux/delay.h>
26 #include <linux/slab.h>
27 #include <linux/ioport.h>
28 #include <sound/core.h>
29 #include <sound/gus.h>
30 #include <sound/control.h>
34 MODULE_AUTHOR("Jaroslav Kysela <perex@suse.cz>");
35 MODULE_DESCRIPTION("Routines for Gravis UltraSound soundcards");
36 MODULE_LICENSE("GPL");
38 static int snd_gus_init_dma_irq(snd_gus_card_t
* gus
, int latches
);
40 int snd_gus_use_inc(snd_gus_card_t
* gus
)
42 if (!try_module_get(gus
->card
->module
))
47 void snd_gus_use_dec(snd_gus_card_t
* gus
)
49 module_put(gus
->card
->module
);
52 static int snd_gus_joystick_info(snd_kcontrol_t
*kcontrol
, snd_ctl_elem_info_t
* uinfo
)
54 uinfo
->type
= SNDRV_CTL_ELEM_TYPE_INTEGER
;
56 uinfo
->value
.integer
.min
= 0;
57 uinfo
->value
.integer
.max
= 31;
61 static int snd_gus_joystick_get(snd_kcontrol_t
* kcontrol
, snd_ctl_elem_value_t
* ucontrol
)
63 snd_gus_card_t
*gus
= snd_kcontrol_chip(kcontrol
);
65 ucontrol
->value
.integer
.value
[0] = gus
->joystick_dac
& 31;
69 static int snd_gus_joystick_put(snd_kcontrol_t
* kcontrol
, snd_ctl_elem_value_t
* ucontrol
)
71 snd_gus_card_t
*gus
= snd_kcontrol_chip(kcontrol
);
76 nval
= ucontrol
->value
.integer
.value
[0] & 31;
77 spin_lock_irqsave(&gus
->reg_lock
, flags
);
78 change
= gus
->joystick_dac
!= nval
;
79 gus
->joystick_dac
= nval
;
80 snd_gf1_write8(gus
, SNDRV_GF1_GB_JOYSTICK_DAC_LEVEL
, gus
->joystick_dac
);
81 spin_unlock_irqrestore(&gus
->reg_lock
, flags
);
85 static snd_kcontrol_new_t snd_gus_joystick_control
= {
86 .iface
= SNDRV_CTL_ELEM_IFACE_CARD
,
87 .name
= "Joystick Speed",
88 .info
= snd_gus_joystick_info
,
89 .get
= snd_gus_joystick_get
,
90 .put
= snd_gus_joystick_put
93 static void snd_gus_init_control(snd_gus_card_t
*gus
)
96 snd_ctl_add(gus
->card
, snd_ctl_new1(&snd_gus_joystick_control
, gus
));
103 static int snd_gus_free(snd_gus_card_t
*gus
)
105 if (gus
->gf1
.res_port2
== NULL
)
107 #if defined(CONFIG_SND_SEQUENCER) || (defined(MODULE) && defined(CONFIG_SND_SEQUENCER_MODULE))
109 snd_device_free(gus
->card
, gus
->seq_dev
);
114 snd_gus_init_dma_irq(gus
, 0);
116 if (gus
->gf1
.res_port1
) {
117 release_resource(gus
->gf1
.res_port1
);
118 kfree_nocheck(gus
->gf1
.res_port1
);
120 if (gus
->gf1
.res_port2
) {
121 release_resource(gus
->gf1
.res_port2
);
122 kfree_nocheck(gus
->gf1
.res_port2
);
124 if (gus
->gf1
.irq
>= 0)
125 free_irq(gus
->gf1
.irq
, (void *) gus
);
126 if (gus
->gf1
.dma1
>= 0) {
127 disable_dma(gus
->gf1
.dma1
);
128 free_dma(gus
->gf1
.dma1
);
130 if (!gus
->equal_dma
&& gus
->gf1
.dma2
>= 0) {
131 disable_dma(gus
->gf1
.dma2
);
132 free_dma(gus
->gf1
.dma2
);
138 static int snd_gus_dev_free(snd_device_t
*device
)
140 snd_gus_card_t
*gus
= device
->device_data
;
141 return snd_gus_free(gus
);
144 int snd_gus_create(snd_card_t
* card
,
146 int irq
, int dma1
, int dma2
,
151 snd_gus_card_t
**rgus
)
155 static snd_device_ops_t ops
= {
156 .dev_free
= snd_gus_dev_free
,
160 gus
= kcalloc(1, sizeof(*gus
), GFP_KERNEL
);
167 gus
->gf1
.port
= port
;
168 /* fill register variables for speedup */
169 gus
->gf1
.reg_page
= GUSP(gus
, GF1PAGE
);
170 gus
->gf1
.reg_regsel
= GUSP(gus
, GF1REGSEL
);
171 gus
->gf1
.reg_data8
= GUSP(gus
, GF1DATAHIGH
);
172 gus
->gf1
.reg_data16
= GUSP(gus
, GF1DATALOW
);
173 gus
->gf1
.reg_irqstat
= GUSP(gus
, IRQSTAT
);
174 gus
->gf1
.reg_dram
= GUSP(gus
, DRAM
);
175 gus
->gf1
.reg_timerctrl
= GUSP(gus
, TIMERCNTRL
);
176 gus
->gf1
.reg_timerdata
= GUSP(gus
, TIMERDATA
);
177 /* allocate resources */
178 if ((gus
->gf1
.res_port1
= request_region(port
, 16, "GUS GF1 (Adlib/SB)")) == NULL
) {
179 snd_printk(KERN_ERR
"gus: can't grab SB port 0x%lx\n", port
);
183 if ((gus
->gf1
.res_port2
= request_region(port
+ 0x100, 12, "GUS GF1 (Synth)")) == NULL
) {
184 snd_printk(KERN_ERR
"gus: can't grab synth port 0x%lx\n", port
+ 0x100);
188 if (irq
>= 0 && request_irq(irq
, snd_gus_interrupt
, SA_INTERRUPT
, "GUS GF1", (void *) gus
)) {
189 snd_printk(KERN_ERR
"gus: can't grab irq %d\n", irq
);
194 if (request_dma(dma1
, "GUS - 1")) {
195 snd_printk(KERN_ERR
"gus: can't grab DMA1 %d\n", dma1
);
199 gus
->gf1
.dma1
= dma1
;
200 if (dma2
>= 0 && dma1
!= dma2
) {
201 if (request_dma(dma2
, "GUS - 2")) {
202 snd_printk(KERN_ERR
"gus: can't grab DMA2 %d\n", dma2
);
206 gus
->gf1
.dma2
= dma2
;
208 gus
->gf1
.dma2
= gus
->gf1
.dma1
;
211 gus
->timer_dev
= timer_dev
;
216 if (pcm_channels
< 0)
218 if (pcm_channels
> 8)
222 gus
->gf1
.effect
= effect
? 1 : 0;
223 gus
->gf1
.active_voices
= voices
;
224 gus
->gf1
.pcm_channels
= pcm_channels
;
225 gus
->gf1
.volume_ramp
= 25;
226 gus
->gf1
.smooth_pan
= 1;
227 spin_lock_init(&gus
->reg_lock
);
228 spin_lock_init(&gus
->voice_alloc
);
229 spin_lock_init(&gus
->active_voice_lock
);
230 spin_lock_init(&gus
->event_lock
);
231 spin_lock_init(&gus
->dma_lock
);
232 spin_lock_init(&gus
->pcm_volume_level_lock
);
233 spin_lock_init(&gus
->uart_cmd_lock
);
234 init_MUTEX(&gus
->dma_mutex
);
235 if ((err
= snd_device_new(card
, SNDRV_DEV_LOWLEVEL
, gus
, &ops
)) < 0) {
244 * Memory detection routine for plain GF1 soundcards
247 static int snd_gus_detect_memory(snd_gus_card_t
* gus
)
252 snd_gf1_poke(gus
, 0L, 0xaa);
253 snd_gf1_poke(gus
, 1L, 0x55);
254 if (snd_gf1_peek(gus
, 0L) != 0xaa || snd_gf1_peek(gus
, 1L) != 0x55) {
255 snd_printk("plain GF1 card at 0x%lx without onboard DRAM?\n", gus
->gf1
.port
);
258 for (idx
= 1, d
= 0xab; idx
< 4; idx
++, d
++) {
260 snd_gf1_poke(gus
, local
, d
);
261 snd_gf1_poke(gus
, local
+ 1, d
+ 1);
262 if (snd_gf1_peek(gus
, local
) != d
||
263 snd_gf1_peek(gus
, local
+ 1) != d
+ 1 ||
264 snd_gf1_peek(gus
, 0L) != 0xaa)
268 gus
->gf1
.memory
= idx
<< 18;
270 gus
->gf1
.memory
= 256 * 1024;
272 for (l
= 0, local
= gus
->gf1
.memory
; l
< 4; l
++, local
-= 256 * 1024) {
273 gus
->gf1
.mem_alloc
.banks_8
[l
].address
=
274 gus
->gf1
.mem_alloc
.banks_8
[l
].size
= 0;
275 gus
->gf1
.mem_alloc
.banks_16
[l
].address
= l
<< 18;
276 gus
->gf1
.mem_alloc
.banks_16
[l
].size
= local
> 0 ? 256 * 1024 : 0;
278 gus
->gf1
.mem_alloc
.banks_8
[0].size
= gus
->gf1
.memory
;
279 return 0; /* some memory were detected */
282 static int snd_gus_init_dma_irq(snd_gus_card_t
* gus
, int latches
)
287 static unsigned char irqs
[16] =
288 {0, 0, 1, 3, 0, 2, 0, 4, 0, 1, 0, 5, 6, 0, 0, 7};
289 static unsigned char dmas
[8] =
290 {6, 1, 0, 2, 0, 3, 4, 5};
292 snd_assert(gus
!= NULL
, return -EINVAL
);
294 snd_assert(card
!= NULL
, return -EINVAL
);
296 gus
->mix_cntrl_reg
&= 0xf8;
297 gus
->mix_cntrl_reg
|= 0x01; /* disable MIC, LINE IN, enable LINE OUT */
298 if (gus
->codec_flag
|| gus
->ess_flag
) {
299 gus
->mix_cntrl_reg
&= ~1; /* enable LINE IN */
300 gus
->mix_cntrl_reg
|= 4; /* enable MIC */
302 dma1
= gus
->gf1
.dma1
;
303 dma1
= dma1
< 0 ? -dma1
: dma1
;
304 dma1
= dmas
[dma1
& 7];
305 dma2
= gus
->gf1
.dma2
;
306 dma2
= dma2
< 0 ? -dma2
: dma2
;
307 dma2
= dmas
[dma2
& 7];
309 printk("dma1 = %i, dma2 = %i\n", gus
->gf1
.dma1
, gus
->gf1
.dma2
);
311 dma1
|= gus
->equal_dma
? 0x40 : (dma2
<< 3);
313 if ((dma1
& 7) == 0 || (dma2
& 7) == 0) {
314 snd_printk("Error! DMA isn't defined.\n");
318 irq
= irq
< 0 ? -irq
: irq
;
319 irq
= irqs
[irq
& 0x0f];
321 snd_printk("Error! IRQ isn't defined.\n");
326 card
->mixer
.mix_ctrl_reg
|= 0x10;
329 spin_lock_irqsave(&gus
->reg_lock
, flags
);
330 outb(5, GUSP(gus
, REGCNTRLS
));
331 outb(gus
->mix_cntrl_reg
, GUSP(gus
, MIXCNTRLREG
));
332 outb(0x00, GUSP(gus
, IRQDMACNTRLREG
));
333 outb(0, GUSP(gus
, REGCNTRLS
));
334 spin_unlock_irqrestore(&gus
->reg_lock
, flags
);
338 spin_lock_irqsave(&gus
->reg_lock
, flags
);
339 outb(0x00 | gus
->mix_cntrl_reg
, GUSP(gus
, MIXCNTRLREG
));
340 outb(dma1
, GUSP(gus
, IRQDMACNTRLREG
));
342 outb(0x40 | gus
->mix_cntrl_reg
, GUSP(gus
, MIXCNTRLREG
));
343 outb(irq
, GUSP(gus
, IRQDMACNTRLREG
));
345 spin_unlock_irqrestore(&gus
->reg_lock
, flags
);
349 spin_lock_irqsave(&gus
->reg_lock
, flags
);
350 outb(0x00 | gus
->mix_cntrl_reg
, GUSP(gus
, MIXCNTRLREG
));
351 outb(dma1
, GUSP(gus
, IRQDMACNTRLREG
));
353 outb(0x40 | gus
->mix_cntrl_reg
, GUSP(gus
, MIXCNTRLREG
));
354 outb(irq
, GUSP(gus
, IRQDMACNTRLREG
));
356 spin_unlock_irqrestore(&gus
->reg_lock
, flags
);
361 gus
->mix_cntrl_reg
|= 0x08; /* enable latches */
363 gus
->mix_cntrl_reg
&= ~0x08; /* disable latches */
364 spin_lock_irqsave(&gus
->reg_lock
, flags
);
365 outb(gus
->mix_cntrl_reg
, GUSP(gus
, MIXCNTRLREG
));
366 outb(0, GUSP(gus
, GF1PAGE
));
367 spin_unlock_irqrestore(&gus
->reg_lock
, flags
);
372 static int snd_gus_check_version(snd_gus_card_t
* gus
)
375 unsigned char val
, rev
;
379 spin_lock_irqsave(&gus
->reg_lock
, flags
);
380 outb(0x20, GUSP(gus
, REGCNTRLS
));
381 val
= inb(GUSP(gus
, REGCNTRLS
));
382 rev
= inb(GUSP(gus
, BOARDVERSION
));
383 spin_unlock_irqrestore(&gus
->reg_lock
, flags
);
384 snd_printdd("GF1 [0x%lx] init - val = 0x%x, rev = 0x%x\n", gus
->gf1
.port
, val
, rev
);
385 strcpy(card
->driver
, "GUS");
386 strcpy(card
->longname
, "Gravis UltraSound Classic (2.4)");
387 if ((val
!= 255 && (val
& 0x06)) || (rev
>= 5 && rev
!= 255)) {
388 if (rev
>= 5 && rev
<= 9) {
391 gus
->ics_flipped
= 1;
392 card
->longname
[27] = '3';
393 card
->longname
[29] = rev
== 5 ? '5' : '7';
395 if (rev
>= 10 && rev
!= 255) {
396 if (rev
>= 10 && rev
<= 11) {
397 strcpy(card
->driver
, "GUS MAX");
398 strcpy(card
->longname
, "Gravis UltraSound MAX");
400 } else if (rev
== 0x30) {
401 strcpy(card
->driver
, "GUS ACE");
402 strcpy(card
->longname
, "Gravis UltraSound Ace");
404 } else if (rev
== 0x50) {
405 strcpy(card
->driver
, "GUS Extreme");
406 strcpy(card
->longname
, "Gravis UltraSound Extreme");
409 snd_printk("unknown GF1 revision number at 0x%lx - 0x%x (0x%x)\n", gus
->gf1
.port
, rev
, val
);
410 snd_printk(" please - report to <perex@suse.cz>\n");
414 strcpy(card
->shortname
, card
->longname
);
415 gus
->uart_enable
= 1; /* standard GUSes doesn't have midi uart trouble */
416 snd_gus_init_control(gus
);
420 static void snd_gus_seq_dev_free(snd_seq_device_t
*seq_dev
)
422 snd_gus_card_t
*gus
= seq_dev
->private_data
;
426 int snd_gus_initialize(snd_gus_card_t
*gus
)
430 if (!gus
->interwave
) {
431 if ((err
= snd_gus_check_version(gus
)) < 0) {
432 snd_printk("version check failed\n");
435 if ((err
= snd_gus_detect_memory(gus
)) < 0)
438 if ((err
= snd_gus_init_dma_irq(gus
, 1)) < 0)
440 #if defined(CONFIG_SND_SEQUENCER) || (defined(MODULE) && defined(CONFIG_SND_SEQUENCER_MODULE))
441 if (snd_seq_device_new(gus
->card
, 1, SNDRV_SEQ_DEV_ID_GUS
,
442 sizeof(snd_gus_card_t
*), &gus
->seq_dev
) >= 0) {
443 strcpy(gus
->seq_dev
->name
, "GUS");
444 *(snd_gus_card_t
**)SNDRV_SEQ_DEVICE_ARGPTR(gus
->seq_dev
) = gus
;
445 gus
->seq_dev
->private_data
= gus
;
446 gus
->seq_dev
->private_free
= snd_gus_seq_dev_free
;
450 gus
->initialized
= 1;
455 EXPORT_SYMBOL(snd_gf1_delay
);
456 EXPORT_SYMBOL(snd_gf1_write8
);
457 EXPORT_SYMBOL(snd_gf1_look8
);
458 EXPORT_SYMBOL(snd_gf1_write16
);
459 EXPORT_SYMBOL(snd_gf1_look16
);
460 EXPORT_SYMBOL(snd_gf1_i_write8
);
461 EXPORT_SYMBOL(snd_gf1_i_look8
);
462 EXPORT_SYMBOL(snd_gf1_i_write16
);
463 EXPORT_SYMBOL(snd_gf1_i_look16
);
464 EXPORT_SYMBOL(snd_gf1_dram_addr
);
465 EXPORT_SYMBOL(snd_gf1_write_addr
);
466 EXPORT_SYMBOL(snd_gf1_poke
);
467 EXPORT_SYMBOL(snd_gf1_peek
);
469 EXPORT_SYMBOL(snd_gf1_alloc_voice
);
470 EXPORT_SYMBOL(snd_gf1_free_voice
);
471 EXPORT_SYMBOL(snd_gf1_ctrl_stop
);
472 EXPORT_SYMBOL(snd_gf1_stop_voice
);
473 EXPORT_SYMBOL(snd_gf1_start
);
474 EXPORT_SYMBOL(snd_gf1_stop
);
476 EXPORT_SYMBOL(snd_gf1_new_mixer
);
478 EXPORT_SYMBOL(snd_gf1_pcm_new
);
480 EXPORT_SYMBOL(snd_gus_use_inc
);
481 EXPORT_SYMBOL(snd_gus_use_dec
);
482 EXPORT_SYMBOL(snd_gus_create
);
483 EXPORT_SYMBOL(snd_gus_initialize
);
485 EXPORT_SYMBOL(snd_gus_interrupt
);
487 EXPORT_SYMBOL(snd_gf1_rawmidi_new
);
489 EXPORT_SYMBOL(snd_gus_dram_write
);
490 EXPORT_SYMBOL(snd_gus_dram_read
);
492 EXPORT_SYMBOL(snd_gf1_lvol_to_gvol_raw
);
493 EXPORT_SYMBOL(snd_gf1_translate_freq
);
495 EXPORT_SYMBOL(snd_gf1_mem_alloc
);
496 EXPORT_SYMBOL(snd_gf1_mem_xfree
);
497 EXPORT_SYMBOL(snd_gf1_mem_free
);
498 EXPORT_SYMBOL(snd_gf1_mem_lock
);
504 static int __init
alsa_gus_init(void)
509 static void __exit
alsa_gus_exit(void)
513 module_init(alsa_gus_init
)
514 module_exit(alsa_gus_exit
)