Linux Audio

Check our new training course

Loading...
Note: File does not exist in v5.9.
  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
 21static volatile int opened, tmr_running;
 22static volatile time_t tmr_offs, tmr_ctr;
 23static volatile unsigned long ticks_offs;
 24static volatile int curr_tempo, curr_timebase;
 25static volatile unsigned long curr_ticks;
 26static volatile unsigned long next_event_time;
 27static unsigned long prev_event_time;
 28
 29static void     poll_def_tmr(unsigned long dummy);
 30static DEFINE_SPINLOCK(lock);
 31static DEFINE_TIMER(def_tmr, poll_def_tmr, 0, 0);
 32
 33static unsigned long
 34tmr2ticks(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
 50static void
 51poll_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
 78static void
 79tmr_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
 93static int
 94def_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
111static void
112def_tmr_close(int dev)
113{
114	opened = tmr_running = 0;
115	del_timer(&def_tmr);
116}
117
118static int
119def_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
180static unsigned long
181def_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!? */
190static 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		
251	case SNDCTL_TMR_METRONOME:
252		/* NOP */
253		break;
254		
255	default:;
256	}
257	return -EINVAL;
258}
259
260static void
261def_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
273struct sound_timer_operations default_sound_timer =
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};