File: /usr/src/linux/drivers/sound/sys_timer.c

1     /*
2      * sound/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 "sound_config.h"
19     
20     static volatile int opened = 0, tmr_running = 0;
21     static volatile time_t tmr_offs, tmr_ctr;
22     static volatile unsigned long ticks_offs;
23     static volatile int curr_tempo, curr_timebase;
24     static volatile unsigned long curr_ticks;
25     static volatile unsigned long next_event_time;
26     static unsigned long prev_event_time;
27     
28     static void     poll_def_tmr(unsigned long dummy);
29     
30     
31     static struct timer_list def_tmr =
32     {function: poll_def_tmr};
33     
34     static unsigned long
35     tmr2ticks(int tmr_value)
36     {
37     	/*
38     	 *    Convert timer ticks to MIDI ticks
39     	 */
40     
41     	unsigned long tmp;
42     	unsigned long scale;
43     
44     	/* tmr_value (ticks per sec) *
45     	   1000000 (usecs per sec) / HZ (ticks per sec) -=> usecs */
46     	tmp = tmr_value * (1000000 / HZ);
47     	scale = (60 * 1000000) / (curr_tempo * curr_timebase);	/* usecs per MIDI tick */
48     	return (tmp + scale / 2) / scale;
49     }
50     
51     static void
52     poll_def_tmr(unsigned long dummy)
53     {
54     
55     	if (opened)
56     	  {
57     
58     		  {
59     			  def_tmr.expires = (1) + jiffies;
60     			  add_timer(&def_tmr);
61     		  };
62     
63     		  if (tmr_running)
64     		    {
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     		    }
74     	  }
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     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     	;
105     
106     	{
107     		def_tmr.expires = (1) + jiffies;
108     		add_timer(&def_tmr);
109     	};
110     
111     	return 0;
112     }
113     
114     static void
115     def_tmr_close(int dev)
116     {
117     	opened = tmr_running = 0;
118     	del_timer(&def_tmr);;
119     }
120     
121     static int
122     def_tmr_event(int dev, unsigned char *event)
123     {
124     	unsigned char   cmd = event[1];
125     	unsigned long   parm = *(int *) &event[4];
126     
127     	switch (cmd)
128     	  {
129     	  case TMR_WAIT_REL:
130     		  parm += prev_event_time;
131     	  case TMR_WAIT_ABS:
132     		  if (parm > 0)
133     		    {
134     			    long            time;
135     
136     			    if (parm <= curr_ticks)	/* It's the time */
137     				    return TIMER_NOT_ARMED;
138     
139     			    time = parm;
140     			    next_event_time = prev_event_time = time;
141     
142     			    return TIMER_ARMED;
143     		    }
144     		  break;
145     
146     	  case TMR_START:
147     		  tmr_reset();
148     		  tmr_running = 1;
149     		  break;
150     
151     	  case TMR_STOP:
152     		  tmr_running = 0;
153     		  break;
154     
155     	  case TMR_CONTINUE:
156     		  tmr_running = 1;
157     		  break;
158     
159     	  case TMR_TEMPO:
160     		  if (parm)
161     		    {
162     			    if (parm < 8)
163     				    parm = 8;
164     			    if (parm > 360)
165     				    parm = 360;
166     			    tmr_offs = tmr_ctr;
167     			    ticks_offs += tmr2ticks(tmr_ctr);
168     			    tmr_ctr = 0;
169     			    curr_tempo = parm;
170     		    }
171     		  break;
172     
173     	  case TMR_ECHO:
174     		  seq_copy_to_input(event, 8);
175     		  break;
176     
177     	  default:;
178     	  }
179     
180     	return TIMER_NOT_ARMED;
181     }
182     
183     static unsigned long
184     def_tmr_get_time(int dev)
185     {
186     	if (!opened)
187     		return 0;
188     
189     	return curr_ticks;
190     }
191     
192     /* same as sound_timer.c:timer_ioctl!? */
193     static int def_tmr_ioctl(int dev, unsigned int cmd, caddr_t arg)
194     {
195     	int val;
196     
197     	switch (cmd) {
198     	case SNDCTL_TMR_SOURCE:
199     		return __put_user(TMR_INTERNAL, (int *)arg);
200     
201     	case SNDCTL_TMR_START:
202     		tmr_reset();
203     		tmr_running = 1;
204     		return 0;
205     
206     	case SNDCTL_TMR_STOP:
207     		tmr_running = 0;
208     		return 0;
209     
210     	case SNDCTL_TMR_CONTINUE:
211     		tmr_running = 1;
212     		return 0;
213     
214     	case SNDCTL_TMR_TIMEBASE:
215     		if (__get_user(val, (int *)arg))
216     			return -EFAULT;
217     		if (val) {
218     			if (val < 1)
219     				val = 1;
220     			if (val > 1000)
221     				val = 1000;
222     			curr_timebase = val;
223     		}
224     		return __put_user(curr_timebase, (int *)arg);
225     
226     	case SNDCTL_TMR_TEMPO:
227     		if (__get_user(val, (int *)arg))
228     			return -EFAULT;
229     		if (val) {
230     			if (val < 8)
231     				val = 8;
232     			if (val > 250)
233     				val = 250;
234     			tmr_offs = tmr_ctr;
235     			ticks_offs += tmr2ticks(tmr_ctr);
236     			tmr_ctr = 0;
237     			curr_tempo = val;
238     			reprogram_timer();
239     		}
240     		return __put_user(curr_tempo, (int *)arg);
241     
242     	case SNDCTL_SEQ_CTRLRATE:
243     		if (__get_user(val, (int *)arg))
244     			return -EFAULT;
245     		if (val != 0)	/* Can't change */
246     			return -EINVAL;
247     		val = ((curr_tempo * curr_timebase) + 30) / 60;
248     		return __put_user(val, (int *)arg);
249     		
250     	case SNDCTL_SEQ_GETTIME:
251     		return __put_user(curr_ticks, (int *)arg);
252     		
253     	case SNDCTL_TMR_METRONOME:
254     		/* NOP */
255     		break;
256     		
257     	default:;
258     	}
259     	return -EINVAL;
260     }
261     
262     static void
263     def_tmr_arm(int dev, long time)
264     {
265     	if (time < 0)
266     		time = curr_ticks + 1;
267     	else if (time <= curr_ticks)	/* It's the time */
268     		return;
269     
270     	next_event_time = prev_event_time = time;
271     
272     	return;
273     }
274     
275     struct sound_timer_operations default_sound_timer =
276     {
277     	owner:		THIS_MODULE,
278     	info:		{"System clock", 0},
279     	priority:	0,	/* Priority */
280     	devlink:	0,	/* Local device link */
281     	open:		def_tmr_open,
282     	close:		def_tmr_close,
283     	event:		def_tmr_event,
284     	get_time:	def_tmr_get_time,
285     	ioctl:		def_tmr_ioctl,
286     	arm_timer:	def_tmr_arm
287     };
288