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

Subversion Repositories or1k

[/] [or1k/] [trunk/] [rc203soc/] [sw/] [uClinux/] [drivers/] [sound/] [sound_timer.c] - Blame information for rev 1765

Details | Compare with Previous | View Log

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

powered by: WebSVN 2.1.0

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