Linux Kernel  3.7.1
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
sys_timer.c
Go to the documentation of this file.
1 /*
2  * sound/oss/sys_timer.c
3  *
4  * The default timer for the Level 2 sequencer interface
5  * Uses the (1/HZ sec) timer of kernel.
6  */
7 /*
8  * Copyright (C) by Hannu Savolainen 1993-1997
9  *
10  * OSS/Free for Linux is distributed under the GNU GENERAL PUBLIC LICENSE (GPL)
11  * Version 2 (June 1991). See the "COPYING" file distributed with this software
12  * for more info.
13  */
14 /*
15  * Thomas Sailer : ioctl code reworked (vmalloc/vfree removed)
16  * Andrew Veliath : adapted tmr2ticks from level 1 sequencer (avoid overflow)
17  */
18 #include <linux/spinlock.h>
19 #include "sound_config.h"
20 
21 static volatile int opened, tmr_running;
22 static volatile time_t tmr_offs, tmr_ctr;
23 static volatile unsigned long ticks_offs;
24 static volatile int curr_tempo, curr_timebase;
25 static volatile unsigned long curr_ticks;
26 static volatile unsigned long next_event_time;
27 static unsigned long prev_event_time;
28 
29 static void poll_def_tmr(unsigned long dummy);
30 static DEFINE_SPINLOCK(lock);
31 static DEFINE_TIMER(def_tmr, poll_def_tmr, 0, 0);
32 
33 static unsigned long
34 tmr2ticks(int tmr_value)
35 {
36  /*
37  * Convert timer ticks to MIDI ticks
38  */
39 
40  unsigned long tmp;
41  unsigned long scale;
42 
43  /* tmr_value (ticks per sec) *
44  1000000 (usecs per sec) / HZ (ticks per sec) -=> usecs */
45  tmp = tmr_value * (1000000 / HZ);
46  scale = (60 * 1000000) / (curr_tempo * curr_timebase); /* usecs per MIDI tick */
47  return (tmp + scale / 2) / scale;
48 }
49 
50 static void
51 poll_def_tmr(unsigned long dummy)
52 {
53 
54  if (opened)
55  {
56 
57  {
58  def_tmr.expires = (1) + jiffies;
59  add_timer(&def_tmr);
60  }
61 
62  if (tmr_running)
63  {
64  spin_lock(&lock);
65  tmr_ctr++;
66  curr_ticks = ticks_offs + tmr2ticks(tmr_ctr);
67 
68  if (curr_ticks >= next_event_time)
69  {
70  next_event_time = (unsigned long) -1;
71  sequencer_timer(0);
72  }
73  spin_unlock(&lock);
74  }
75  }
76 }
77 
78 static void
79 tmr_reset(void)
80 {
81  unsigned long flags;
82 
83  spin_lock_irqsave(&lock,flags);
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  spin_unlock_irqrestore(&lock,flags);
91 }
92 
93 static int
94 def_tmr_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  {
104  def_tmr.expires = (1) + jiffies;
105  add_timer(&def_tmr);
106  }
107 
108  return 0;
109 }
110 
111 static void
112 def_tmr_close(int dev)
113 {
114  opened = tmr_running = 0;
115  del_timer(&def_tmr);
116 }
117 
118 static int
119 def_tmr_event(int dev, unsigned char *event)
120 {
121  unsigned char cmd = event[1];
122  unsigned long parm = *(int *) &event[4];
123 
124  switch (cmd)
125  {
126  case TMR_WAIT_REL:
127  parm += prev_event_time;
128  case TMR_WAIT_ABS:
129  if (parm > 0)
130  {
131  long time;
132 
133  if (parm <= curr_ticks) /* It's the time */
134  return TIMER_NOT_ARMED;
135 
136  time = parm;
137  next_event_time = prev_event_time = time;
138 
139  return TIMER_ARMED;
140  }
141  break;
142 
143  case TMR_START:
144  tmr_reset();
145  tmr_running = 1;
146  break;
147 
148  case TMR_STOP:
149  tmr_running = 0;
150  break;
151 
152  case TMR_CONTINUE:
153  tmr_running = 1;
154  break;
155 
156  case TMR_TEMPO:
157  if (parm)
158  {
159  if (parm < 8)
160  parm = 8;
161  if (parm > 360)
162  parm = 360;
163  tmr_offs = tmr_ctr;
164  ticks_offs += tmr2ticks(tmr_ctr);
165  tmr_ctr = 0;
166  curr_tempo = parm;
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 def_tmr_get_time(int dev)
182 {
183  if (!opened)
184  return 0;
185 
186  return curr_ticks;
187 }
188 
189 /* same as sound_timer.c:timer_ioctl!? */
190 static int def_tmr_ioctl(int dev, unsigned int cmd, void __user *arg)
191 {
192  int __user *p = arg;
193  int val;
194 
195  switch (cmd) {
196  case SNDCTL_TMR_SOURCE:
197  return __put_user(TMR_INTERNAL, p);
198 
199  case SNDCTL_TMR_START:
200  tmr_reset();
201  tmr_running = 1;
202  return 0;
203 
204  case SNDCTL_TMR_STOP:
205  tmr_running = 0;
206  return 0;
207 
208  case SNDCTL_TMR_CONTINUE:
209  tmr_running = 1;
210  return 0;
211 
212  case SNDCTL_TMR_TIMEBASE:
213  if (__get_user(val, p))
214  return -EFAULT;
215  if (val) {
216  if (val < 1)
217  val = 1;
218  if (val > 1000)
219  val = 1000;
220  curr_timebase = val;
221  }
222  return __put_user(curr_timebase, p);
223 
224  case SNDCTL_TMR_TEMPO:
225  if (__get_user(val, p))
226  return -EFAULT;
227  if (val) {
228  if (val < 8)
229  val = 8;
230  if (val > 250)
231  val = 250;
232  tmr_offs = tmr_ctr;
233  ticks_offs += tmr2ticks(tmr_ctr);
234  tmr_ctr = 0;
235  curr_tempo = val;
236  reprogram_timer();
237  }
238  return __put_user(curr_tempo, p);
239 
240  case SNDCTL_SEQ_CTRLRATE:
241  if (__get_user(val, p))
242  return -EFAULT;
243  if (val != 0) /* Can't change */
244  return -EINVAL;
245  val = ((curr_tempo * curr_timebase) + 30) / 60;
246  return __put_user(val, p);
247 
248  case SNDCTL_SEQ_GETTIME:
249  return __put_user(curr_ticks, p);
250 
252  /* NOP */
253  break;
254 
255  default:;
256  }
257  return -EINVAL;
258 }
259 
260 static void
261 def_tmr_arm(int dev, long time)
262 {
263  if (time < 0)
264  time = curr_ticks + 1;
265  else if (time <= curr_ticks) /* It's the time */
266  return;
267 
268  next_event_time = prev_event_time = time;
269 
270  return;
271 }
272 
274 {
275  .owner = THIS_MODULE,
276  .info = {"System clock", 0},
277  .priority = 0, /* Priority */
278  .devlink = 0, /* Local device link */
279  .open = def_tmr_open,
280  .close = def_tmr_close,
281  .event = def_tmr_event,
282  .get_time = def_tmr_get_time,
283  .ioctl = def_tmr_ioctl,
284  .arm_timer = def_tmr_arm
285 };