]>
Commit | Line | Data |
---|---|---|
1a59d1b8 | 1 | // SPDX-License-Identifier: GPL-2.0-or-later |
1da177e4 LT |
2 | /* |
3 | * Routines for Gravis UltraSound soundcards - Timers | |
c1017a4c | 4 | * Copyright (c) by Jaroslav Kysela <perex@perex.cz> |
1da177e4 LT |
5 | * |
6 | * GUS have similar timers as AdLib (OPL2/OPL3 chips). | |
1da177e4 LT |
7 | */ |
8 | ||
1da177e4 LT |
9 | #include <linux/time.h> |
10 | #include <sound/core.h> | |
11 | #include <sound/gus.h> | |
12 | ||
13 | /* | |
14 | * Timer 1 - 80us | |
15 | */ | |
16 | ||
5e2da206 | 17 | static int snd_gf1_timer1_start(struct snd_timer * timer) |
1da177e4 LT |
18 | { |
19 | unsigned long flags; | |
20 | unsigned char tmp; | |
21 | unsigned int ticks; | |
5e2da206 | 22 | struct snd_gus_card *gus; |
1da177e4 LT |
23 | |
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); | |
32 | return 0; | |
33 | } | |
34 | ||
5e2da206 | 35 | static int snd_gf1_timer1_stop(struct snd_timer * timer) |
1da177e4 LT |
36 | { |
37 | unsigned long flags; | |
38 | unsigned char tmp; | |
5e2da206 | 39 | struct snd_gus_card *gus; |
1da177e4 LT |
40 | |
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); | |
46 | return 0; | |
47 | } | |
48 | ||
49 | /* | |
50 | * Timer 2 - 320us | |
51 | */ | |
52 | ||
5e2da206 | 53 | static int snd_gf1_timer2_start(struct snd_timer * timer) |
1da177e4 LT |
54 | { |
55 | unsigned long flags; | |
56 | unsigned char tmp; | |
57 | unsigned int ticks; | |
5e2da206 | 58 | struct snd_gus_card *gus; |
1da177e4 LT |
59 | |
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); | |
68 | return 0; | |
69 | } | |
70 | ||
5e2da206 | 71 | static int snd_gf1_timer2_stop(struct snd_timer * timer) |
1da177e4 LT |
72 | { |
73 | unsigned long flags; | |
74 | unsigned char tmp; | |
5e2da206 | 75 | struct snd_gus_card *gus; |
1da177e4 LT |
76 | |
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); | |
82 | return 0; | |
83 | } | |
84 | ||
85 | /* | |
86 | ||
87 | */ | |
88 | ||
5e2da206 | 89 | static void snd_gf1_interrupt_timer1(struct snd_gus_card * gus) |
1da177e4 | 90 | { |
5e2da206 | 91 | struct snd_timer *timer = gus->gf1.timer1; |
1da177e4 LT |
92 | |
93 | if (timer == NULL) | |
94 | return; | |
95 | snd_timer_interrupt(timer, timer->sticks); | |
96 | } | |
97 | ||
5e2da206 | 98 | static void snd_gf1_interrupt_timer2(struct snd_gus_card * gus) |
1da177e4 | 99 | { |
5e2da206 | 100 | struct snd_timer *timer = gus->gf1.timer2; |
1da177e4 LT |
101 | |
102 | if (timer == NULL) | |
103 | return; | |
104 | snd_timer_interrupt(timer, timer->sticks); | |
105 | } | |
106 | ||
107 | /* | |
108 | ||
109 | */ | |
110 | ||
5e2da206 | 111 | static struct snd_timer_hardware snd_gf1_timer1 = |
1da177e4 LT |
112 | { |
113 | .flags = SNDRV_TIMER_HW_STOP, | |
114 | .resolution = 80000, | |
115 | .ticks = 256, | |
116 | .start = snd_gf1_timer1_start, | |
117 | .stop = snd_gf1_timer1_stop, | |
118 | }; | |
119 | ||
5e2da206 | 120 | static struct snd_timer_hardware snd_gf1_timer2 = |
1da177e4 LT |
121 | { |
122 | .flags = SNDRV_TIMER_HW_STOP, | |
123 | .resolution = 320000, | |
124 | .ticks = 256, | |
125 | .start = snd_gf1_timer2_start, | |
126 | .stop = snd_gf1_timer2_stop, | |
127 | }; | |
128 | ||
5e2da206 | 129 | static void snd_gf1_timer1_free(struct snd_timer *timer) |
1da177e4 | 130 | { |
5e2da206 | 131 | struct snd_gus_card *gus = timer->private_data; |
1da177e4 LT |
132 | gus->gf1.timer1 = NULL; |
133 | } | |
134 | ||
5e2da206 | 135 | static void snd_gf1_timer2_free(struct snd_timer *timer) |
1da177e4 | 136 | { |
5e2da206 | 137 | struct snd_gus_card *gus = timer->private_data; |
1da177e4 LT |
138 | gus->gf1.timer2 = NULL; |
139 | } | |
140 | ||
5e2da206 | 141 | void snd_gf1_timers_init(struct snd_gus_card * gus) |
1da177e4 | 142 | { |
5e2da206 TI |
143 | struct snd_timer *timer; |
144 | struct snd_timer_id tid; | |
1da177e4 LT |
145 | |
146 | if (gus->gf1.timer1 != NULL || gus->gf1.timer2 != NULL) | |
147 | return; | |
148 | ||
149 | gus->gf1.interrupt_handler_timer1 = snd_gf1_interrupt_timer1; | |
150 | gus->gf1.interrupt_handler_timer2 = snd_gf1_interrupt_timer2; | |
151 | ||
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; | |
156 | tid.subdevice = 0; | |
157 | ||
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; | |
163 | } | |
164 | gus->gf1.timer1 = timer; | |
165 | ||
166 | tid.device++; | |
167 | ||
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; | |
173 | } | |
174 | gus->gf1.timer2 = timer; | |
175 | } | |
176 | ||
5e2da206 | 177 | void snd_gf1_timers_done(struct snd_gus_card * gus) |
1da177e4 LT |
178 | { |
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; | |
183 | } | |
184 | if (gus->gf1.timer2) { | |
185 | snd_device_free(gus->card, gus->gf1.timer2); | |
186 | gus->gf1.timer2 = NULL; | |
187 | } | |
188 | } |