This source file includes following definitions.
- timer_command
- arm_timer
- tmr2ticks
- reprogram_timer
- tmr_reset
- timer_open
- timer_close
- timer_event
- timer_get_time
- timer_ioctl
- timer_arm
- sound_timer_interrupt
- sound_timer_init
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31 #define SEQUENCER_C
32 #include "sound_config.h"
33
34 #ifdef CONFIGURE_SOUNDCARD
35
36 #if !defined(EXCLUDE_SEQUENCER) && (!defined(EXCLUDE_GUS) || (!defined(EXCLUDE_PAS) && !defined(EXCLUDE_YM3812)))
37
38 static volatile int initialized = 0, opened = 0, tmr_running = 0;
39 static volatile time_t tmr_offs, tmr_ctr;
40 static volatile unsigned long ticks_offs;
41 static volatile int curr_tempo, curr_timebase;
42 static volatile unsigned long curr_ticks;
43 static volatile unsigned long next_event_time;
44 static unsigned long prev_event_time;
45 static volatile int select_addr, data_addr;
46 static volatile int curr_timer = 0;
47 static volatile unsigned long usecs_per_tmr;
48
49
50 static void
51 timer_command (unsigned int addr, unsigned int val)
52 {
53 int i;
54
55 OUTB ((unsigned char) (addr & 0xff), select_addr);
56
57 for (i = 0; i < 2; i++)
58 INB (select_addr);
59
60 OUTB ((unsigned char) (val & 0xff), data_addr);
61
62 for (i = 0; i < 2; i++)
63 INB (select_addr);
64 }
65
66 static void
67 arm_timer (int timer, unsigned int interval)
68 {
69
70 curr_timer = timer;
71
72 if (timer == 1)
73 {
74 gus_write8 (0x46, 256 - interval);
75 gus_write8 (0x45, 0x04);
76 timer_command (0x04, 0x01);
77 }
78 else
79 {
80 gus_write8 (0x47, 256 - interval);
81 gus_write8 (0x45, 0x08);
82 timer_command (0x04, 0x02);
83 }
84 }
85
86 static unsigned long
87 tmr2ticks (int tmr_value)
88 {
89
90
91
92
93 unsigned long tmp;
94 unsigned long scale;
95
96 tmp = tmr_value * usecs_per_tmr;
97
98 scale = (60 * 1000000) / (curr_tempo * curr_timebase);
99
100 return (tmp + (scale / 2)) / scale;
101 }
102
103 static void
104 reprogram_timer (void)
105 {
106 unsigned long usecs_per_tick;
107 int timer_no, resolution;
108 int divisor;
109
110 usecs_per_tick = (60 * 1000000) / (curr_tempo * curr_timebase);
111
112
113
114
115 if (usecs_per_tick < 2000)
116 usecs_per_tick = 2000;
117
118 if (usecs_per_tick > (256 * 80))
119 {
120 timer_no = 2;
121 resolution = 320;
122 }
123 else
124 {
125 timer_no = 1;
126 resolution = 80;
127 }
128
129 divisor = (usecs_per_tick + (resolution / 2)) / resolution;
130 usecs_per_tmr = divisor * resolution;
131
132 arm_timer (timer_no, divisor);
133 }
134
135 static void
136 tmr_reset (void)
137 {
138 unsigned long flags;
139
140 DISABLE_INTR (flags);
141 tmr_offs = 0;
142 ticks_offs = 0;
143 tmr_ctr = 0;
144 next_event_time = 0xffffffff;
145 prev_event_time = 0;
146 curr_ticks = 0;
147 RESTORE_INTR (flags);
148 }
149
150 static int
151 timer_open (int dev, int mode)
152 {
153 if (opened)
154 return RET_ERROR (EBUSY);
155
156 tmr_reset ();
157 curr_tempo = 60;
158 curr_timebase = HZ;
159 opened = 1;
160 reprogram_timer ();
161
162 return 0;
163 }
164
165 static void
166 timer_close (int dev)
167 {
168 opened = tmr_running = 0;
169 gus_write8 (0x45, 0);
170 }
171
172 static int
173 timer_event (int dev, unsigned char *event)
174 {
175 unsigned char cmd = event[1];
176 unsigned long parm = *(int *) &event[4];
177
178 switch (cmd)
179 {
180 case TMR_WAIT_REL:
181 parm += prev_event_time;
182 case TMR_WAIT_ABS:
183 if (parm > 0)
184 {
185 long time;
186
187 if (parm <= curr_ticks)
188 return TIMER_NOT_ARMED;
189
190 time = parm;
191 next_event_time = prev_event_time = time;
192
193 return TIMER_ARMED;
194 }
195 break;
196
197 case TMR_START:
198 tmr_reset ();
199 tmr_running = 1;
200 reprogram_timer ();
201 break;
202
203 case TMR_STOP:
204 tmr_running = 0;
205 break;
206
207 case TMR_CONTINUE:
208 tmr_running = 1;
209 reprogram_timer ();
210 break;
211
212 case TMR_TEMPO:
213 if (parm)
214 {
215 if (parm < 8)
216 parm = 8;
217 if (parm > 250)
218 parm = 250;
219 tmr_offs = tmr_ctr;
220 ticks_offs += tmr2ticks (tmr_ctr);
221 tmr_ctr = 0;
222 curr_tempo = parm;
223 reprogram_timer ();
224 }
225 break;
226
227 case TMR_ECHO:
228 seq_copy_to_input (event, 8);
229 break;
230
231 default:;
232 }
233
234 return TIMER_NOT_ARMED;
235 }
236
237 static unsigned long
238 timer_get_time (int dev)
239 {
240 if (!opened)
241 return 0;
242
243 return curr_ticks;
244 }
245
246 static int
247 timer_ioctl (int dev,
248 unsigned int cmd, unsigned int arg)
249 {
250 switch (cmd)
251 {
252 case SNDCTL_TMR_SOURCE:
253 return IOCTL_OUT (arg, TMR_INTERNAL);
254 break;
255
256 case SNDCTL_TMR_START:
257 tmr_reset ();
258 tmr_running = 1;
259 return 0;
260 break;
261
262 case SNDCTL_TMR_STOP:
263 tmr_running = 0;
264 return 0;
265 break;
266
267 case SNDCTL_TMR_CONTINUE:
268 tmr_running = 1;
269 return 0;
270 break;
271
272 case SNDCTL_TMR_TIMEBASE:
273 {
274 int val = IOCTL_IN (arg);
275
276 if (val)
277 {
278 if (val < 1)
279 val = 1;
280 if (val > 1000)
281 val = 1000;
282 curr_timebase = val;
283 }
284
285 return IOCTL_OUT (arg, curr_timebase);
286 }
287 break;
288
289 case SNDCTL_TMR_TEMPO:
290 {
291 int val = IOCTL_IN (arg);
292
293 if (val)
294 {
295 if (val < 8)
296 val = 8;
297 if (val > 250)
298 val = 250;
299 tmr_offs = tmr_ctr;
300 ticks_offs += tmr2ticks (tmr_ctr);
301 tmr_ctr = 0;
302 curr_tempo = val;
303 reprogram_timer ();
304 }
305
306 return IOCTL_OUT (arg, curr_tempo);
307 }
308 break;
309
310 case SNDCTL_SEQ_CTRLRATE:
311 if (IOCTL_IN (arg) != 0)
312 return RET_ERROR (EINVAL);
313
314 return IOCTL_OUT (arg, ((curr_tempo * curr_timebase) + 30) / 60);
315 break;
316
317 case SNDCTL_TMR_METRONOME:
318
319 break;
320
321 default:
322 }
323
324 return RET_ERROR (EINVAL);
325 }
326
327 static void
328 timer_arm (int dev, long time)
329 {
330 if (time < 0)
331 time = curr_ticks + 1;
332 else if (time <= curr_ticks)
333 return;
334
335 next_event_time = prev_event_time = time;
336
337 return;
338 }
339
340 static struct sound_timer_operations sound_timer =
341 {
342 {"OPL-3/GUS Timer", 0},
343 1,
344 0,
345 timer_open,
346 timer_close,
347 timer_event,
348 timer_get_time,
349 timer_ioctl,
350 timer_arm
351 };
352
353 void
354 sound_timer_interrupt (void)
355 {
356 gus_write8 (0x45, 0);
357 timer_command (4, 0x80);
358
359 if (!opened)
360 return;
361
362 if (curr_timer == 1)
363 gus_write8 (0x45, 0x04);
364 else
365 gus_write8 (0x45, 0x08);
366
367 if (!tmr_running)
368 return;
369
370 tmr_ctr++;
371 curr_ticks = ticks_offs + tmr2ticks (tmr_ctr);
372
373 if (curr_ticks >= next_event_time)
374 {
375 next_event_time = 0xffffffff;
376 sequencer_timer ();
377 }
378 }
379
380 void
381 sound_timer_init (int io_base)
382 {
383 int n;
384
385 if (initialized)
386 return;
387
388 select_addr = io_base;
389 data_addr = io_base + 1;
390
391 initialized = 1;
392
393 #if 1
394 if (num_sound_timers >= MAX_TIMER_DEV)
395 n = 0;
396 else
397 n = num_sound_timers++;
398 #else
399 n = 0;
400 #endif
401
402 sound_timer_devs[n] = &sound_timer;
403 }
404
405 #endif
406 #endif