Initial import from FreeBSD RELENG_4:
[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  */
30
31 #define SEQUENCER_C
32 #include <i386/isa/sound/sound_config.h>
33
34 #if     NSND > 0
35
36 #if defined(CONFIG_SEQUENCER)
37
38 static volatile int opened = 0, tmr_running = 0;
39 static volatile time_t tmr_offs, tmr_ctr;
40 static volatile u_long ticks_offs;
41 static volatile int curr_tempo, curr_timebase;
42 static volatile u_long curr_ticks;
43 static volatile u_long next_event_time;
44 static u_long prev_event_time;
45
46 static void     poll_def_tmr(void *dummy);
47
48 static u_long
49 tmr2ticks(int tmr_value)
50 {
51     /*
52      * Convert system timer ticks (hz) to MIDI ticks (divide # of MIDI
53      * ticks/minute by # of system ticks/minute).
54      */
55
56     return ((tmr_value * curr_tempo * curr_timebase) + (30 * hz)) / (60 * hz);
57 }
58
59 static void
60 poll_def_tmr(void *dummy)
61 {
62
63     if (opened) {
64
65         timeout( poll_def_tmr, 0, 1);;
66
67         if (tmr_running) {
68             tmr_ctr++;
69             curr_ticks = ticks_offs + tmr2ticks(tmr_ctr);
70
71             if (curr_ticks >= next_event_time) {
72                 next_event_time = 0xffffffff;
73                 sequencer_timer(0);
74             }
75         }
76     }
77 }
78
79 static void
80 tmr_reset(void)
81 {
82     u_long   flags;
83
84     flags = splhigh();
85     tmr_offs = 0;
86     ticks_offs = 0;
87     tmr_ctr = 0;
88     next_event_time = 0xffffffff;
89     prev_event_time = 0;
90     curr_ticks = 0;
91     splx(flags);
92 }
93
94 static int
95 def_tmr_open(int dev, int mode)
96 {
97     if (opened)
98         return -(EBUSY);
99
100     tmr_reset();
101     curr_tempo = 60;
102     curr_timebase = hz;
103     opened = 1;
104
105     timeout( poll_def_tmr, 0, 1);;
106
107     return 0;
108 }
109
110 static void
111 def_tmr_close(int dev)
112 {
113     opened = tmr_running = 0;
114 }
115
116 static int
117 def_tmr_event(int dev, u_char *event)
118 {
119     u_char   cmd = event[1];
120     u_long   parm = *(int *) &event[4];
121
122     switch (cmd) {
123     case TMR_WAIT_REL:
124         parm += prev_event_time;
125     case TMR_WAIT_ABS:
126         if (parm > 0) {
127             long            time;
128
129             if (parm <= curr_ticks)     /* It's the time */
130                 return TIMER_NOT_ARMED;
131
132             time = parm;
133             next_event_time = prev_event_time = time;
134
135             return TIMER_ARMED;
136         }
137         break;
138
139     case TMR_START:
140         tmr_reset();
141         tmr_running = 1;
142         break;
143
144     case TMR_STOP:
145         tmr_running = 0;
146         break;
147
148     case TMR_CONTINUE:
149         tmr_running = 1;
150         break;
151
152     case TMR_TEMPO:
153         if (parm) {
154             RANGE (parm, 8, 360) ;
155             tmr_offs = tmr_ctr;
156             ticks_offs += tmr2ticks(tmr_ctr);
157             tmr_ctr = 0;
158             curr_tempo = parm;
159         }
160         break;
161
162     case TMR_ECHO:
163         seq_copy_to_input(event, 8);
164         break;
165
166     default:;
167     }
168
169     return TIMER_NOT_ARMED;
170 }
171
172 static u_long
173 def_tmr_get_time(int dev)
174 {
175     if (!opened)
176         return 0;
177
178     return curr_ticks;
179 }
180
181 static int
182 def_tmr_ioctl(int dev, u_int cmd, ioctl_arg arg)
183 {
184     switch (cmd) {
185     case SNDCTL_TMR_SOURCE:
186         return *(int *) arg = TMR_INTERNAL;
187         break;
188
189     case SNDCTL_TMR_START:
190         tmr_reset();
191         tmr_running = 1;
192         return 0;
193         break;
194
195     case SNDCTL_TMR_STOP:
196         tmr_running = 0;
197         return 0;
198         break;
199
200     case SNDCTL_TMR_CONTINUE:
201         tmr_running = 1;
202         return 0;
203         break;
204
205     case SNDCTL_TMR_TIMEBASE:
206         {
207             int             val = (*(int *) arg);
208
209             if (val) {
210                 RANGE (val, 1, 1000) ;
211                 curr_timebase = val;
212             }
213             return *(int *) arg = curr_timebase;
214         }
215         break;
216
217     case SNDCTL_TMR_TEMPO:
218         {
219             int             val = (*(int *) arg);
220
221             if (val) {
222                 RANGE (val, 8, 250) ;
223                 tmr_offs = tmr_ctr;
224                 ticks_offs += tmr2ticks(tmr_ctr);
225                 tmr_ctr = 0;
226                 curr_tempo = val;
227             }
228             return *(int *) arg = curr_tempo;
229         }
230         break;
231
232     case SNDCTL_SEQ_CTRLRATE:
233         if ((*(int *) arg) != 0)        /* Can't change */
234             return -(EINVAL);
235
236         return *(int *) arg = ((curr_tempo * curr_timebase) + 30) / 60;
237         break;
238
239     case SNDCTL_TMR_METRONOME:
240         /* NOP */
241         break;
242
243     default:;
244     }
245
246     return -(EINVAL);
247 }
248
249 static void
250 def_tmr_arm(int dev, long time)
251 {
252     if (time < 0)
253         time = curr_ticks + 1;
254     else if (time <= curr_ticks)        /* It's the time */
255         return;
256
257     next_event_time = prev_event_time = time;
258
259     return;
260 }
261
262 struct sound_timer_operations default_sound_timer =
263 {
264         {"System clock", 0},
265         0,                      /* Priority */
266         0,                      /* Local device link */
267         def_tmr_open,
268         def_tmr_close,
269         def_tmr_event,
270         def_tmr_get_time,
271         def_tmr_ioctl,
272         def_tmr_arm
273 };
274
275 #endif
276 #endif  /* NSND > 0 */