1 // SPDX-License-Identifier: GPL-2.0-or-later
3 * Routines for Gravis UltraSound soundcards - Timers
4 * Copyright (c) by Jaroslav Kysela <perex@perex.cz>
6 * GUS have similar timers as AdLib (OPL2/OPL3 chips).
9 #include <linux/time.h>
10 #include <sound/core.h>
11 #include <sound/gus.h>
17 static int snd_gf1_timer1_start(struct snd_timer
* timer
)
22 struct snd_gus_card
*gus
;
24 gus
= snd_timer_chip(timer
);
25 spin_lock_irqsave(&gus
->reg_lock
, flags
);
26 ticks
= timer
->sticks
;
27 tmp
= (gus
->gf1
.timer_enabled
|= 4);
28 snd_gf1_write8(gus
, SNDRV_GF1_GB_ADLIB_TIMER_1
, 256 - ticks
); /* timer 1 count */
29 snd_gf1_write8(gus
, SNDRV_GF1_GB_SOUND_BLASTER_CONTROL
, tmp
); /* enable timer 1 IRQ */
30 snd_gf1_adlib_write(gus
, 0x04, tmp
>> 2); /* timer 2 start */
31 spin_unlock_irqrestore(&gus
->reg_lock
, flags
);
35 static int snd_gf1_timer1_stop(struct snd_timer
* timer
)
39 struct snd_gus_card
*gus
;
41 gus
= snd_timer_chip(timer
);
42 spin_lock_irqsave(&gus
->reg_lock
, flags
);
43 tmp
= (gus
->gf1
.timer_enabled
&= ~4);
44 snd_gf1_write8(gus
, SNDRV_GF1_GB_SOUND_BLASTER_CONTROL
, tmp
); /* disable timer #1 */
45 spin_unlock_irqrestore(&gus
->reg_lock
, flags
);
53 static int snd_gf1_timer2_start(struct snd_timer
* timer
)
58 struct snd_gus_card
*gus
;
60 gus
= snd_timer_chip(timer
);
61 spin_lock_irqsave(&gus
->reg_lock
, flags
);
62 ticks
= timer
->sticks
;
63 tmp
= (gus
->gf1
.timer_enabled
|= 8);
64 snd_gf1_write8(gus
, SNDRV_GF1_GB_ADLIB_TIMER_2
, 256 - ticks
); /* timer 2 count */
65 snd_gf1_write8(gus
, SNDRV_GF1_GB_SOUND_BLASTER_CONTROL
, tmp
); /* enable timer 2 IRQ */
66 snd_gf1_adlib_write(gus
, 0x04, tmp
>> 2); /* timer 2 start */
67 spin_unlock_irqrestore(&gus
->reg_lock
, flags
);
71 static int snd_gf1_timer2_stop(struct snd_timer
* timer
)
75 struct snd_gus_card
*gus
;
77 gus
= snd_timer_chip(timer
);
78 spin_lock_irqsave(&gus
->reg_lock
, flags
);
79 tmp
= (gus
->gf1
.timer_enabled
&= ~8);
80 snd_gf1_write8(gus
, SNDRV_GF1_GB_SOUND_BLASTER_CONTROL
, tmp
); /* disable timer #1 */
81 spin_unlock_irqrestore(&gus
->reg_lock
, flags
);
89 static void snd_gf1_interrupt_timer1(struct snd_gus_card
* gus
)
91 struct snd_timer
*timer
= gus
->gf1
.timer1
;
95 snd_timer_interrupt(timer
, timer
->sticks
);
98 static void snd_gf1_interrupt_timer2(struct snd_gus_card
* gus
)
100 struct snd_timer
*timer
= gus
->gf1
.timer2
;
104 snd_timer_interrupt(timer
, timer
->sticks
);
111 static const struct snd_timer_hardware snd_gf1_timer1
=
113 .flags
= SNDRV_TIMER_HW_STOP
,
116 .start
= snd_gf1_timer1_start
,
117 .stop
= snd_gf1_timer1_stop
,
120 static const struct snd_timer_hardware snd_gf1_timer2
=
122 .flags
= SNDRV_TIMER_HW_STOP
,
123 .resolution
= 320000,
125 .start
= snd_gf1_timer2_start
,
126 .stop
= snd_gf1_timer2_stop
,
129 static void snd_gf1_timer1_free(struct snd_timer
*timer
)
131 struct snd_gus_card
*gus
= timer
->private_data
;
132 gus
->gf1
.timer1
= NULL
;
135 static void snd_gf1_timer2_free(struct snd_timer
*timer
)
137 struct snd_gus_card
*gus
= timer
->private_data
;
138 gus
->gf1
.timer2
= NULL
;
141 void snd_gf1_timers_init(struct snd_gus_card
* gus
)
143 struct snd_timer
*timer
;
144 struct snd_timer_id tid
;
146 if (gus
->gf1
.timer1
!= NULL
|| gus
->gf1
.timer2
!= NULL
)
149 gus
->gf1
.interrupt_handler_timer1
= snd_gf1_interrupt_timer1
;
150 gus
->gf1
.interrupt_handler_timer2
= snd_gf1_interrupt_timer2
;
152 tid
.dev_class
= SNDRV_TIMER_CLASS_CARD
;
153 tid
.dev_sclass
= SNDRV_TIMER_SCLASS_NONE
;
154 tid
.card
= gus
->card
->number
;
155 tid
.device
= gus
->timer_dev
;
158 if (snd_timer_new(gus
->card
, "GF1 timer", &tid
, &timer
) >= 0) {
159 strcpy(timer
->name
, "GF1 timer #1");
160 timer
->private_data
= gus
;
161 timer
->private_free
= snd_gf1_timer1_free
;
162 timer
->hw
= snd_gf1_timer1
;
164 gus
->gf1
.timer1
= timer
;
168 if (snd_timer_new(gus
->card
, "GF1 timer", &tid
, &timer
) >= 0) {
169 strcpy(timer
->name
, "GF1 timer #2");
170 timer
->private_data
= gus
;
171 timer
->private_free
= snd_gf1_timer2_free
;
172 timer
->hw
= snd_gf1_timer2
;
174 gus
->gf1
.timer2
= timer
;
177 void snd_gf1_timers_done(struct snd_gus_card
* gus
)
179 snd_gf1_set_default_handlers(gus
, SNDRV_GF1_HANDLER_TIMER1
| SNDRV_GF1_HANDLER_TIMER2
);
180 if (gus
->gf1
.timer1
) {
181 snd_device_free(gus
->card
, gus
->gf1
.timer1
);
182 gus
->gf1
.timer1
= NULL
;
184 if (gus
->gf1
.timer2
) {
185 snd_device_free(gus
->card
, gus
->gf1
.timer2
);
186 gus
->gf1
.timer2
= NULL
;