Merge from vendor branch LIBSTDC++:
[dragonfly.git] / sys / dev / sound / isa / i386 / sys_timer.c
1 /*
2  * sound/sys_timer.c
3  * 
4  * The default timer for the Level 2 sequencer interface.
5  * Uses the (100hz) timer of kernel.
6  * 
7  * Copyright by Hannu Savolainen 1993
8  * 
9  * Redistribution and use in source and binary forms, with or without
10  * modification, are permitted provided that the following conditions are
11  * met: 1. Redistributions of source code must retain the above copyright
12  * notice, this list of conditions and the following disclaimer. 2.
13  * Redistributions in binary form must reproduce the above copyright notice,
14  * this list of conditions and the following disclaimer in the documentation
15  * and/or other materials provided with the distribution.
16  * 
17  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND ANY
18  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
19  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
20  * DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
21  * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
23  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
24  * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27  * SUCH DAMAGE.
28  * 
29  * $DragonFly: src/sys/dev/sound/isa/i386/Attic/sys_timer.c,v 1.2 2003/08/07 21:17:12 dillon Exp $
30  */
31
32 #define SEQUENCER_C
33 #include "sound_config.h"
34
35 #if     NSND > 0
36
37 #if defined(CONFIG_SEQUENCER)
38
39 static volatile int opened = 0, tmr_running = 0;
40 static volatile time_t tmr_offs, tmr_ctr;
41 static volatile u_long ticks_offs;
42 static volatile int curr_tempo, curr_timebase;
43 static volatile u_long curr_ticks;
44 static volatile u_long next_event_time;
45 static u_long prev_event_time;
46
47 static void     poll_def_tmr(void *dummy);
48
49 static u_long
50 tmr2ticks(int tmr_value)
51 {
52     /*
53      * Convert system timer ticks (hz) to MIDI ticks (divide # of MIDI
54      * ticks/minute by # of system ticks/minute).
55      */
56
57     return ((tmr_value * curr_tempo * curr_timebase) + (30 * hz)) / (60 * hz);
58 }
59
60 static void
61 poll_def_tmr(void *dummy)
62 {
63
64     if (opened) {
65
66         timeout( poll_def_tmr, 0, 1);;
67
68         if (tmr_running) {
69             tmr_ctr++;
70             curr_ticks = ticks_offs + tmr2ticks(tmr_ctr);
71
72             if (curr_ticks >= next_event_time) {
73                 next_event_time = 0xffffffff;
74                 sequencer_timer(0);
75             }
76         }
77     }
78 }
79
80 static void
81 tmr_reset(void)
82 {
83     u_long   flags;
84
85     flags = splhigh();
86     tmr_offs = 0;
87     ticks_offs = 0;
88     tmr_ctr = 0;
89     next_event_time = 0xffffffff;
90     prev_event_time = 0;
91     curr_ticks = 0;
92     splx(flags);
93 }
94
95 static int
96 def_tmr_open(int dev, int mode)
97 {
98     if (opened)
99         return -(EBUSY);
100
101     tmr_reset();
102     curr_tempo = 60;
103     curr_timebase = hz;
104     opened = 1;
105
106     timeout( poll_def_tmr, 0, 1);;
107
108     return 0;
109 }
110
111 static void
112 def_tmr_close(int dev)
113 {
114     opened = tmr_running = 0;
115 }
116
117 static int
118 def_tmr_event(int dev, u_char *event)
119 {
120     u_char   cmd = event[1];
121     u_long   parm = *(int *) &event[4];
122
123     switch (cmd) {
124     case TMR_WAIT_REL:
125         parm += prev_event_time;
126     case TMR_WAIT_ABS:
127         if (parm > 0) {
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         break;
144
145     case TMR_STOP:
146         tmr_running = 0;
147         break;
148
149     case TMR_CONTINUE:
150         tmr_running = 1;
151         break;
152
153     case TMR_TEMPO:
154         if (parm) {
155             RANGE (parm, 8, 360) ;
156             tmr_offs = tmr_ctr;
157             ticks_offs += tmr2ticks(tmr_ctr);
158             tmr_ctr = 0;
159             curr_tempo = parm;
160         }
161         break;
162
163     case TMR_ECHO:
164         seq_copy_to_input(event, 8);
165         break;
166
167     default:;
168     }
169
170     return TIMER_NOT_ARMED;
171 }
172
173 static u_long
174 def_tmr_get_time(int dev)
175 {
176     if (!opened)
177         return 0;
178
179     return curr_ticks;
180 }
181
182 static int
183 def_tmr_ioctl(int dev, u_int cmd, ioctl_arg arg)
184 {
185     switch (cmd) {
186     case SNDCTL_TMR_SOURCE:
187         return *(int *) arg = TMR_INTERNAL;
188         break;
189
190     case SNDCTL_TMR_START:
191         tmr_reset();
192         tmr_running = 1;
193         return 0;
194         break;
195
196     case SNDCTL_TMR_STOP:
197         tmr_running = 0;
198         return 0;
199         break;
200
201     case SNDCTL_TMR_CONTINUE:
202         tmr_running = 1;
203         return 0;
204         break;
205
206     case SNDCTL_TMR_TIMEBASE:
207         {
208             int             val = (*(int *) arg);
209
210             if (val) {
211                 RANGE (val, 1, 1000) ;
212                 curr_timebase = val;
213             }
214             return *(int *) arg = curr_timebase;
215         }
216         break;
217
218     case SNDCTL_TMR_TEMPO:
219         {
220             int             val = (*(int *) arg);
221
222             if (val) {
223                 RANGE (val, 8, 250) ;
224                 tmr_offs = tmr_ctr;
225                 ticks_offs += tmr2ticks(tmr_ctr);
226                 tmr_ctr = 0;
227                 curr_tempo = val;
228             }
229             return *(int *) arg = curr_tempo;
230         }
231         break;
232
233     case SNDCTL_SEQ_CTRLRATE:
234         if ((*(int *) arg) != 0)        /* Can't change */
235             return -(EINVAL);
236
237         return *(int *) arg = ((curr_tempo * curr_timebase) + 30) / 60;
238         break;
239
240     case SNDCTL_TMR_METRONOME:
241         /* NOP */
242         break;
243
244     default:;
245     }
246
247     return -(EINVAL);
248 }
249
250 static void
251 def_tmr_arm(int dev, long time)
252 {
253     if (time < 0)
254         time = curr_ticks + 1;
255     else if (time <= curr_ticks)        /* It's the time */
256         return;
257
258     next_event_time = prev_event_time = time;
259
260     return;
261 }
262
263 struct sound_timer_operations default_sound_timer =
264 {
265         {"System clock", 0},
266         0,                      /* Priority */
267         0,                      /* Local device link */
268         def_tmr_open,
269         def_tmr_close,
270         def_tmr_event,
271         def_tmr_get_time,
272         def_tmr_ioctl,
273         def_tmr_arm
274 };
275
276 #endif
277 #endif  /* NSND > 0 */