OpenCores
URL https://opencores.org/ocsvn/or1k/or1k/trunk

Subversion Repositories or1k

[/] [or1k/] [trunk/] [linux/] [linux-2.4/] [drivers/] [sound/] [sound_timer.c] - Blame information for rev 1765

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 1275 phoenix
/*
2
 * sound/sound_timer.c
3
 */
4
/*
5
 * Copyright (C) by Hannu Savolainen 1993-1997
6
 *
7
 * OSS/Free for Linux is distributed under the GNU GENERAL PUBLIC LICENSE (GPL)
8
 * Version 2 (June 1991). See the "COPYING" file distributed with this software
9
 * for more info.
10
 */
11
/*
12
 * Thomas Sailer   : ioctl code reworked (vmalloc/vfree removed)
13
 */
14
#include <linux/string.h>
15
 
16
 
17
#include "sound_config.h"
18
 
19
static volatile int initialized, opened, tmr_running;
20
static volatile time_t tmr_offs, tmr_ctr;
21
static volatile unsigned long ticks_offs;
22
static volatile int curr_tempo, curr_timebase;
23
static volatile unsigned long curr_ticks;
24
static volatile unsigned long next_event_time;
25
static unsigned long prev_event_time;
26
static volatile unsigned long usecs_per_tmr;    /* Length of the current interval */
27
 
28
static struct sound_lowlev_timer *tmr;
29
 
30
static unsigned long tmr2ticks(int tmr_value)
31
{
32
        /*
33
         *    Convert timer ticks to MIDI ticks
34
         */
35
 
36
        unsigned long tmp;
37
        unsigned long scale;
38
 
39
        tmp = tmr_value * usecs_per_tmr;        /* Convert to usecs */
40
        scale = (60 * 1000000) / (curr_tempo * curr_timebase);  /* usecs per MIDI tick */
41
        return (tmp + (scale / 2)) / scale;
42
}
43
 
44
void reprogram_timer(void)
45
{
46
        unsigned long   usecs_per_tick;
47
 
48
        /*
49
         *      The user is changing the timer rate before setting a timer
50
         *      slap, bad bad not allowed.
51
         */
52
 
53
        if(!tmr)
54
                return;
55
 
56
        usecs_per_tick = (60 * 1000000) / (curr_tempo * curr_timebase);
57
 
58
        /*
59
         * Don't kill the system by setting too high timer rate
60
         */
61
        if (usecs_per_tick < 2000)
62
                usecs_per_tick = 2000;
63
 
64
        usecs_per_tmr = tmr->tmr_start(tmr->dev, usecs_per_tick);
65
}
66
 
67
void sound_timer_syncinterval(unsigned int new_usecs)
68
{
69
        /*
70
         *    This routine is called by the hardware level if
71
         *      the clock frequency has changed for some reason.
72
         */
73
        tmr_offs = tmr_ctr;
74
        ticks_offs += tmr2ticks(tmr_ctr);
75
        tmr_ctr = 0;
76
        usecs_per_tmr = new_usecs;
77
}
78
 
79
static void tmr_reset(void)
80
{
81
        unsigned long   flags;
82
 
83
        save_flags(flags);
84
        cli();
85
        tmr_offs = 0;
86
        ticks_offs = 0;
87
        tmr_ctr = 0;
88
        next_event_time = (unsigned long) -1;
89
        prev_event_time = 0;
90
        curr_ticks = 0;
91
        restore_flags(flags);
92
}
93
 
94
static int timer_open(int dev, int mode)
95
{
96
        if (opened)
97
                return -EBUSY;
98
        tmr_reset();
99
        curr_tempo = 60;
100
        curr_timebase = 100;
101
        opened = 1;
102
        reprogram_timer();
103
        return 0;
104
}
105
 
106
static void timer_close(int dev)
107
{
108
        opened = tmr_running = 0;
109
        tmr->tmr_disable(tmr->dev);
110
}
111
 
112
static int timer_event(int dev, unsigned char *event)
113
{
114
        unsigned char cmd = event[1];
115
        unsigned long parm = *(int *) &event[4];
116
 
117
        switch (cmd)
118
        {
119
                case TMR_WAIT_REL:
120
                        parm += prev_event_time;
121
                case TMR_WAIT_ABS:
122
                        if (parm > 0)
123
                        {
124
                                long time;
125
 
126
                                if (parm <= curr_ticks) /* It's the time */
127
                                        return TIMER_NOT_ARMED;
128
                                time = parm;
129
                                next_event_time = prev_event_time = time;
130
                                return TIMER_ARMED;
131
                        }
132
                        break;
133
 
134
                case TMR_START:
135
                        tmr_reset();
136
                        tmr_running = 1;
137
                        reprogram_timer();
138
                        break;
139
 
140
                case TMR_STOP:
141
                        tmr_running = 0;
142
                        break;
143
 
144
                case TMR_CONTINUE:
145
                        tmr_running = 1;
146
                        reprogram_timer();
147
                        break;
148
 
149
                case TMR_TEMPO:
150
                        if (parm)
151
                        {
152
                                if (parm < 8)
153
                                        parm = 8;
154
                                if (parm > 250)
155
                                        parm = 250;
156
                                tmr_offs = tmr_ctr;
157
                                ticks_offs += tmr2ticks(tmr_ctr);
158
                                tmr_ctr = 0;
159
                                curr_tempo = parm;
160
                                reprogram_timer();
161
                        }
162
                        break;
163
 
164
                case TMR_ECHO:
165
                        seq_copy_to_input(event, 8);
166
                        break;
167
 
168
                default:;
169
        }
170
        return TIMER_NOT_ARMED;
171
}
172
 
173
static unsigned long timer_get_time(int dev)
174
{
175
        if (!opened)
176
                return 0;
177
        return curr_ticks;
178
}
179
 
180
static int timer_ioctl(int dev, unsigned int cmd, caddr_t arg)
181
{
182
        int val;
183
 
184
        switch (cmd)
185
        {
186
                case SNDCTL_TMR_SOURCE:
187
                        val = TMR_INTERNAL;
188
                        break;
189
 
190
                case SNDCTL_TMR_START:
191
                        tmr_reset();
192
                        tmr_running = 1;
193
                        return 0;
194
 
195
                case SNDCTL_TMR_STOP:
196
                        tmr_running = 0;
197
                        return 0;
198
 
199
                case SNDCTL_TMR_CONTINUE:
200
                        tmr_running = 1;
201
                        return 0;
202
 
203
                case SNDCTL_TMR_TIMEBASE:
204
                        if (get_user(val, (int *)arg))
205
                                return -EFAULT;
206
                        if (val)
207
                        {
208
                                if (val < 1)
209
                                        val = 1;
210
                                if (val > 1000)
211
                                        val = 1000;
212
                                curr_timebase = val;
213
                        }
214
                        val = curr_timebase;
215
                        break;
216
 
217
                case SNDCTL_TMR_TEMPO:
218
                        if (get_user(val, (int *)arg))
219
                                return -EFAULT;
220
                        if (val)
221
                        {
222
                                if (val < 8)
223
                                        val = 8;
224
                                if (val > 250)
225
                                        val = 250;
226
                                tmr_offs = tmr_ctr;
227
                                ticks_offs += tmr2ticks(tmr_ctr);
228
                                tmr_ctr = 0;
229
                                curr_tempo = val;
230
                                reprogram_timer();
231
                        }
232
                        val = curr_tempo;
233
                        break;
234
 
235
                case SNDCTL_SEQ_CTRLRATE:
236
                        if (get_user(val, (int *)arg))
237
                                return -EFAULT;
238
                        if (val != 0)    /* Can't change */
239
                                return -EINVAL;
240
                        val = ((curr_tempo * curr_timebase) + 30) / 60;
241
                        break;
242
 
243
                case SNDCTL_SEQ_GETTIME:
244
                        val = curr_ticks;
245
                        break;
246
 
247
                case SNDCTL_TMR_METRONOME:
248
                default:
249
                        return -EINVAL;
250
        }
251
        return put_user(val, (int *)arg);
252
}
253
 
254
static void timer_arm(int dev, long time)
255
{
256
        if (time < 0)
257
                time = curr_ticks + 1;
258
        else if (time <= curr_ticks)    /* It's the time */
259
                return;
260
 
261
        next_event_time = prev_event_time = time;
262
        return;
263
}
264
 
265
static struct sound_timer_operations sound_timer =
266
{
267
        owner:          THIS_MODULE,
268
        info:           {"Sound Timer", 0},
269
        priority:       1,      /* Priority */
270
        devlink:        0,       /* Local device link */
271
        open:           timer_open,
272
        close:          timer_close,
273
        event:          timer_event,
274
        get_time:       timer_get_time,
275
        ioctl:          timer_ioctl,
276
        arm_timer:      timer_arm
277
};
278
 
279
void sound_timer_interrupt(void)
280
{
281
        if (!opened)
282
                return;
283
 
284
        tmr->tmr_restart(tmr->dev);
285
 
286
        if (!tmr_running)
287
                return;
288
 
289
        tmr_ctr++;
290
        curr_ticks = ticks_offs + tmr2ticks(tmr_ctr);
291
 
292
        if (curr_ticks >= next_event_time)
293
        {
294
                next_event_time = (unsigned long) -1;
295
                sequencer_timer(0);
296
        }
297
}
298
 
299
void  sound_timer_init(struct sound_lowlev_timer *t, char *name)
300
{
301
        int n;
302
 
303
        if (initialized)
304
        {
305
                if (t->priority <= tmr->priority)
306
                        return; /* There is already a similar or better timer */
307
                tmr = t;
308
                return;
309
        }
310
        initialized = 1;
311
        tmr = t;
312
 
313
        n = sound_alloc_timerdev();
314
        if (n == -1)
315
                n = 0;           /* Overwrite the system timer */
316
        strcpy(sound_timer.info.name, name);
317
        sound_timer_devs[n] = &sound_timer;
318
}

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.