• Home
  • History
  • Annotate
  • Line#
  • Navigate
  • Raw
  • Download
  • only in /asuswrt-rt-n18u-9.0.0.4.380.2695/release/src-rt-6.x.4708/linux/linux-2.6/sound/oss/
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};
286