1 /*
2 * This is the timer engine of /dev/music for FreeBSD.
3 *
4 * (C) 2002 Seigo Tanimura
5 *
6 * Redistribution and use in source and binary forms, with or
7 * without modification, are permitted provided that the following
8 * conditions are met:
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above
12 * copyright notice, this list of conditions and the following
13 * disclaimer in the documentation and/or other materials provided
14 * with the distribution.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS
17 * IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
19 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
20 * AUTHOR OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
21 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
22 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
24 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
25 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
26 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
27 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 *
29 * $FreeBSD: releng/5.1/sys/dev/sound/midi/timer.c 111119 2003-02-19 05:47:46Z imp $
30 *
31 */
32
33 #include <dev/sound/midi/midi.h>
34 #include <dev/sound/midi/sequencer.h>
35
36 #define TMR2TICKS(scp, tmr_val) \
37 ((((tmr_val) * (scp)->tempo * (scp)->timebase) + (30 * hz)) / (60 * hz))
38 #define CURTICKS(scp) \
39 ((scp)->ticks_offset + (scp)->ticks_cur - (scp)->ticks_base)
40
41 struct systmr_timer_softc {
42 int running;
43
44 u_long ticks_offset;
45 u_long ticks_base;
46 u_long ticks_cur;
47
48 int tempo;
49 int timebase;
50
51 u_long nexteventtime;
52 u_long preveventtime;
53
54 struct callout timer;
55 };
56
57 static timeout_t systmr_timer;
58 static void systmr_reset(timerdev_info *tmd);
59 static u_long systmr_time(void);
60
61 static tmr_open_t systmr_open;
62 static tmr_close_t systmr_close;
63 static tmr_event_t systmr_event;
64 static tmr_gettime_t systmr_gettime;
65 static tmr_ioctl_t systmr_ioctl;
66 static tmr_armtimer_t systmr_armtimer;
67
68 static timerdev_info systmr_timerdev = {
69 "System clock",
70 0,
71 0,
72 systmr_open,
73 systmr_close,
74 systmr_event,
75 systmr_gettime,
76 systmr_ioctl,
77 systmr_armtimer,
78 };
79
80 static TAILQ_HEAD(,_timerdev_info) timer_info;
81 static struct mtx timerinfo_mtx;
82 static int timerinfo_mtx_init;
83 static int ntimer;
84
85
86 /* Install a system timer. */
87 int
88 timerdev_install(void)
89 {
90 int ret;
91 timerdev_info *tmd;
92 struct systmr_timer_softc *scp;
93
94 SEQ_DEBUG(printf("timerdev_install: install a new timer.\n"));
95
96 ret = 0;
97 tmd = NULL;
98 scp = NULL;
99
100 scp = malloc(sizeof(*scp), M_DEVBUF, M_WAITOK | M_ZERO);
101 if (scp == NULL) {
102 ret = ENOMEM;
103 goto fail;
104 }
105
106 tmd = create_timerdev_info_unit(&systmr_timerdev);
107 if (tmd == NULL) {
108 ret = ENOMEM;
109 goto fail;
110 }
111
112 tmd->softc = scp;
113 callout_init(&scp->timer, 0);
114
115 mtx_unlock(&tmd->mtx);
116
117 SEQ_DEBUG(printf("timerdev_install: installed a new timer, unit %d.\n", tmd->unit));
118
119 return (0);
120
121 fail:
122 if (scp != NULL)
123 free(scp, M_DEVBUF);
124 if (tmd != NULL) {
125 TAILQ_REMOVE(&timer_info, tmd, tmd_link);
126 free(tmd, M_DEVBUF);
127 }
128
129 SEQ_DEBUG(printf("timerdev_install: installation failed.\n"));
130
131 return (ret);
132 }
133
134 /* Create a new timer device info structure. */
135 timerdev_info *
136 create_timerdev_info_unit(timerdev_info *tmdinf)
137 {
138 int unit;
139 timerdev_info *tmd, *tmdnew;
140
141 /* XXX */
142 if (!timerinfo_mtx_init) {
143 timerinfo_mtx_init = 1;
144 mtx_init(&timerinfo_mtx, "tmrinf", NULL, MTX_DEF);
145 TAILQ_INIT(&timer_info);
146 }
147
148 /* As malloc(9) might block, allocate timerdev_info now. */
149 tmdnew = malloc(sizeof(timerdev_info), M_DEVBUF, M_WAITOK | M_ZERO);
150 if (tmdnew == NULL)
151 return NULL;
152 bcopy(tmdinf, tmdnew, sizeof(timerdev_info));
153 mtx_init(&tmdnew->mtx, "tmrmtx", NULL, MTX_DEF);
154
155 mtx_lock(&timerinfo_mtx);
156
157 ntimer++;
158
159 for (unit = 0 ; ; unit++) {
160 TAILQ_FOREACH(tmd, &timer_info, tmd_link) {
161 if (tmd->unit == unit)
162 break;
163 }
164 if (tmd == NULL)
165 break;
166 }
167
168 tmdnew->unit = unit;
169 mtx_lock(&tmdnew->mtx);
170 tmd = TAILQ_FIRST(&timer_info);
171 while (tmd != NULL) {
172 if (tmd->prio < tmdnew->prio)
173 break;
174 tmd = TAILQ_NEXT(tmd, tmd_link);
175 }
176 if (tmd != NULL)
177 TAILQ_INSERT_BEFORE(tmd, tmdnew, tmd_link);
178 else
179 TAILQ_INSERT_TAIL(&timer_info, tmdnew, tmd_link);
180
181 mtx_unlock(&timerinfo_mtx);
182
183 return (tmdnew);
184 }
185
186 /*
187 * a small utility function which, given a unit number, returns
188 * a pointer to the associated timerdev_info struct.
189 */
190 timerdev_info *
191 get_timerdev_info_unit(int unit)
192 {
193 timerdev_info *tmd;
194
195 /* XXX */
196 if (!timerinfo_mtx_init) {
197 timerinfo_mtx_init = 1;
198 mtx_init(&timerinfo_mtx, "tmrinf", NULL, MTX_DEF);
199 TAILQ_INIT(&timer_info);
200 }
201
202 mtx_lock(&timerinfo_mtx);
203 TAILQ_FOREACH(tmd, &timer_info, tmd_link) {
204 mtx_lock(&tmd->mtx);
205 if (tmd->unit == unit && tmd->seq == NULL)
206 break;
207 mtx_unlock(&tmd->mtx);
208 }
209 mtx_unlock(&timerinfo_mtx);
210
211 return tmd;
212 }
213
214 /*
215 * a small utility function which returns a pointer
216 * to the best preferred timerdev_info struct with
217 * no sequencer.
218 */
219 timerdev_info *
220 get_timerdev_info(void)
221 {
222 timerdev_info *tmd;
223
224 /* XXX */
225 if (!timerinfo_mtx_init) {
226 timerinfo_mtx_init = 1;
227 mtx_init(&timerinfo_mtx, "tmrinf", NULL, MTX_DEF);
228 TAILQ_INIT(&timer_info);
229 }
230
231 mtx_lock(&timerinfo_mtx);
232 TAILQ_FOREACH(tmd, &timer_info, tmd_link) {
233 mtx_lock(&tmd->mtx);
234 if (tmd->seq == NULL)
235 break;
236 mtx_unlock(&tmd->mtx);
237 }
238 mtx_unlock(&timerinfo_mtx);
239
240 return tmd;
241 }
242
243
244 /* ARGSUSED */
245 static void
246 systmr_timer(void *d)
247 {
248 timerdev_info *tmd;
249 struct systmr_timer_softc *scp;
250 void *seq;
251
252 tmd = (timerdev_info *)d;
253 scp = (struct systmr_timer_softc *)tmd->softc;
254 seq = NULL;
255
256 mtx_lock(&tmd->mtx);
257
258 if (tmd->opened) {
259 callout_reset(&scp->timer, 1, systmr_timer, tmd);
260
261 if (scp->running) {
262 scp->ticks_cur = TMR2TICKS(scp, systmr_time());
263
264 if (CURTICKS(scp) >= scp->nexteventtime) {
265 SEQ_DEBUG(printf("systmr_timer: CURTICKS %lu, call the sequencer.\n", CURTICKS(scp)));
266 scp->nexteventtime = ULONG_MAX;
267 seq = tmd->seq;
268 }
269 }
270 }
271
272 mtx_unlock(&tmd->mtx);
273
274 if (seq != NULL)
275 seq_timer(seq);
276 }
277
278 static void
279 systmr_reset(timerdev_info *tmd)
280 {
281 struct systmr_timer_softc *scp;
282
283 scp = (struct systmr_timer_softc *)tmd->softc;
284
285 mtx_assert(&tmd->mtx, MA_OWNED);
286
287 SEQ_DEBUG(printf("systmr_reset: unit %d.\n", tmd->unit));
288
289 scp->ticks_offset = 0;
290 scp->ticks_base = scp->ticks_cur = TMR2TICKS(scp, systmr_time());
291
292 scp->nexteventtime = ULONG_MAX;
293 scp->preveventtime = 0;
294 }
295
296 static u_long
297 systmr_time(void)
298 {
299 struct timeval timecopy;
300
301 getmicrotime(&timecopy);
302 return timecopy.tv_usec / (1000000 / hz) + (u_long) timecopy.tv_sec * hz;
303 }
304
305
306 /* ARGSUSED */
307 static int
308 systmr_open(timerdev_info *tmd, int oflags, int devtype, struct thread *td)
309 {
310 struct systmr_timer_softc *scp;
311
312 scp = (struct systmr_timer_softc *)tmd->softc;
313
314 SEQ_DEBUG(printf("systmr_open: unit %d.\n", tmd->unit));
315
316 mtx_lock(&tmd->mtx);
317
318 if (tmd->opened) {
319 mtx_unlock(&tmd->mtx);
320 return (EBUSY);
321 }
322
323 systmr_reset(tmd);
324 scp->tempo = 60;
325 scp->timebase = hz;
326 tmd->opened = 1;
327
328 callout_reset(&scp->timer, 1, systmr_timer, tmd);
329
330 mtx_unlock(&tmd->mtx);
331
332 return (0);
333 }
334
335 static int
336 systmr_close(timerdev_info *tmd, int fflag, int devtype, struct thread *td)
337 {
338 struct systmr_timer_softc *scp;
339
340 scp = (struct systmr_timer_softc *)tmd->softc;
341
342 SEQ_DEBUG(printf("systmr_close: unit %d.\n", tmd->unit));
343
344 mtx_lock(&tmd->mtx);
345
346 tmd->opened = 0;
347 scp->running = 0;
348
349 callout_stop(&scp->timer);
350
351 mtx_unlock(&tmd->mtx);
352
353 return (0);
354 }
355
356 static int
357 systmr_event(timerdev_info *tmd, u_char *ev)
358 {
359 struct systmr_timer_softc *scp;
360 u_char cmd;
361 u_long parm, t;
362 int ret;
363 void * seq;
364
365 scp = (struct systmr_timer_softc *)tmd->softc;
366 cmd = ev[1];
367 parm = *(int *)&ev[4];
368 ret = MORE;
369
370 SEQ_DEBUG(printf("systmr_event: unit %d, cmd %s, parm %lu.\n",
371 tmd->unit, midi_cmdname(cmd, cmdtab_timer), parm));
372
373 mtx_lock(&tmd->mtx);
374
375 switch (cmd) {
376 case TMR_WAIT_REL:
377 parm += scp->preveventtime;
378 /* FALLTHRU */
379 case TMR_WAIT_ABS:
380 if (parm > 0) {
381 if (parm <= CURTICKS(scp))
382 break;
383 t = parm;
384 scp->nexteventtime = scp->preveventtime = t;
385 ret = TIMERARMED;
386 break;
387 }
388 break;
389
390 case TMR_START:
391 systmr_reset(tmd);
392 scp->running = 1;
393 break;
394
395 case TMR_STOP:
396 scp->running = 0;
397 break;
398
399 case TMR_CONTINUE:
400 scp->running = 1;
401 break;
402
403 case TMR_TEMPO:
404 if (parm > 0) {
405 RANGE(parm, 8, 360);
406 scp->ticks_offset += scp->ticks_cur
407 - scp->ticks_base;
408 scp->ticks_base = scp->ticks_cur;
409 scp->tempo = parm;
410 }
411 break;
412
413 case TMR_ECHO:
414 seq = tmd->seq;
415 mtx_unlock(&tmd->mtx);
416 seq_copytoinput(seq, ev, 8);
417 mtx_lock(&tmd->mtx);
418 break;
419 }
420
421 mtx_unlock(&tmd->mtx);
422
423 SEQ_DEBUG(printf("systmr_event: timer %s.\n",
424 ret == TIMERARMED ? "armed" : "not armed"));
425
426 return (ret);
427 }
428
429 static int
430 systmr_gettime(timerdev_info *tmd, u_long *t)
431 {
432 struct systmr_timer_softc *scp;
433 int ret;
434
435 scp = (struct systmr_timer_softc *)tmd->softc;
436
437 SEQ_DEBUG(printf("systmr_gettime: unit %d.\n", tmd->unit));
438
439 mtx_lock(&tmd->mtx);
440
441 if (!tmd->opened || t == NULL) {
442 ret = EINVAL;
443 goto fail;
444 }
445
446 *t = CURTICKS(scp);
447 SEQ_DEBUG(printf("systmr_gettime: ticks %lu.\n", *t));
448
449 fail:
450 mtx_unlock(&tmd->mtx);
451
452 return (0);
453 }
454
455 static int
456 systmr_ioctl(timerdev_info *tmd, u_long cmd, caddr_t data, int fflag, struct thread *td)
457 {
458 struct systmr_timer_softc *scp;
459 int ret, val;
460
461 scp = (struct systmr_timer_softc *)tmd->softc;
462 ret = 0;
463
464 SEQ_DEBUG(printf("systmr_ioctl: unit %d, cmd %s.\n",
465 tmd->unit, midi_cmdname(cmd, cmdtab_seqioctl)));
466
467 switch (cmd) {
468 case SNDCTL_TMR_SOURCE:
469 *(int *)data = TMR_INTERNAL;
470 break;
471
472 case SNDCTL_TMR_START:
473 mtx_lock(&tmd->mtx);
474 systmr_reset(tmd);
475 scp->running = 1;
476 mtx_unlock(&tmd->mtx);
477 break;
478
479 case SNDCTL_TMR_STOP:
480 mtx_lock(&tmd->mtx);
481 scp->running = 0;
482 mtx_unlock(&tmd->mtx);
483 break;
484
485 case SNDCTL_TMR_CONTINUE:
486 mtx_lock(&tmd->mtx);
487 scp->running = 1;
488 mtx_unlock(&tmd->mtx);
489 break;
490
491 case SNDCTL_TMR_TIMEBASE:
492 val = *(int *)data;
493 mtx_lock(&tmd->mtx);
494 if (val > 0) {
495 RANGE(val, 1, 1000);
496 scp->timebase = val;
497 }
498 *(int *)data = scp->timebase;
499 mtx_unlock(&tmd->mtx);
500 SEQ_DEBUG(printf("systmr_ioctl: timebase %d.\n", *(int *)data));
501 break;
502
503 case SNDCTL_TMR_TEMPO:
504 val = *(int *)data;
505 mtx_lock(&tmd->mtx);
506 if (val > 0) {
507 RANGE(val, 8, 360);
508 scp->ticks_offset += scp->ticks_cur
509 - scp->ticks_base;
510 scp->ticks_base = scp->ticks_cur;
511 scp->tempo = val;
512 }
513 *(int *)data = scp->tempo;
514 SEQ_DEBUG(printf("systmr_ioctl: tempo %d.\n", *(int *)data));
515 mtx_unlock(&tmd->mtx);
516 break;
517
518 case SNDCTL_SEQ_CTRLRATE:
519 val = *(int *)data;
520 if (val > 0)
521 ret = EINVAL;
522 else {
523 mtx_lock(&tmd->mtx);
524 *(int *)data = ((scp->tempo * scp->timebase) + 30) / 60;
525 mtx_unlock(&tmd->mtx);
526 SEQ_DEBUG(printf("systmr_ioctl: ctrlrate %d.\n", *(int *)data));
527 }
528 break;
529
530 case SNDCTL_TMR_METRONOME:
531 /* NOP. */
532 break;
533
534 case SNDCTL_TMR_SELECT:
535 /* NOP. */
536 break;
537
538 default:
539 ret = EINVAL;
540 }
541
542 return (ret);
543 }
544
545 static int
546 systmr_armtimer(timerdev_info *tmd, u_long t)
547 {
548 struct systmr_timer_softc *scp;
549
550 scp = (struct systmr_timer_softc *)tmd->softc;
551
552 SEQ_DEBUG(printf("systmr_armtimer: unit %d, t %lu.\n", tmd->unit, t));
553
554 mtx_lock(&tmd->mtx);
555
556 if (t < 0)
557 t = CURTICKS(scp) + 1;
558 else if (t > CURTICKS(scp))
559 scp->nexteventtime = scp->preveventtime = t;
560
561 mtx_unlock(&tmd->mtx);
562
563 return (0);
564 }
Cache object: b576cefd877f321f223a35cb54e1b0f8
|