Add the system default timer engine.
This commit is contained in:
parent
995231304d
commit
5ddd093d23
564
sys/dev/sound/midi/timer.c
Normal file
564
sys/dev/sound/midi/timer.c
Normal file
@ -0,0 +1,564 @@
|
||||
/*
|
||||
* This is the timer engine of /dev/music for FreeBSD.
|
||||
*
|
||||
* (C) 2002 Seigo Tanimura
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or
|
||||
* without modification, are permitted provided that the following
|
||||
* conditions are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above
|
||||
* copyright notice, this list of conditions and the following
|
||||
* disclaimer in the documentation and/or other materials provided
|
||||
* with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS
|
||||
* IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
|
||||
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
|
||||
* AUTHOR OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
||||
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* $FreeBSD$
|
||||
*
|
||||
*/
|
||||
|
||||
#include <dev/sound/midi/midi.h>
|
||||
#include <dev/sound/midi/sequencer.h>
|
||||
|
||||
#define TMR2TICKS(scp, tmr_val) \
|
||||
((((tmr_val) * (scp)->tempo * (scp)->timebase) + (30 * hz)) / (60 * hz))
|
||||
#define CURTICKS(scp) \
|
||||
((scp)->ticks_offset + (scp)->ticks_cur - (scp)->ticks_base)
|
||||
|
||||
struct systmr_timer_softc {
|
||||
int running;
|
||||
|
||||
u_long ticks_offset;
|
||||
u_long ticks_base;
|
||||
u_long ticks_cur;
|
||||
|
||||
int tempo;
|
||||
int timebase;
|
||||
|
||||
u_long nexteventtime;
|
||||
u_long preveventtime;
|
||||
|
||||
struct callout timer;
|
||||
};
|
||||
|
||||
static timeout_t systmr_timer;
|
||||
static void systmr_reset(timerdev_info *tmd);
|
||||
static u_long systmr_time(void);
|
||||
|
||||
static tmr_open_t systmr_open;
|
||||
static tmr_close_t systmr_close;
|
||||
static tmr_event_t systmr_event;
|
||||
static tmr_gettime_t systmr_gettime;
|
||||
static tmr_ioctl_t systmr_ioctl;
|
||||
static tmr_armtimer_t systmr_armtimer;
|
||||
|
||||
static timerdev_info systmr_timerdev = {
|
||||
"System clock",
|
||||
0,
|
||||
0,
|
||||
systmr_open,
|
||||
systmr_close,
|
||||
systmr_event,
|
||||
systmr_gettime,
|
||||
systmr_ioctl,
|
||||
systmr_armtimer,
|
||||
};
|
||||
|
||||
static TAILQ_HEAD(,_timerdev_info) timer_info;
|
||||
static struct mtx timerinfo_mtx;
|
||||
static int timerinfo_mtx_init;
|
||||
static int ntimer;
|
||||
|
||||
|
||||
/* Install a system timer. */
|
||||
int
|
||||
timerdev_install(void)
|
||||
{
|
||||
int ret;
|
||||
timerdev_info *tmd;
|
||||
struct systmr_timer_softc *scp;
|
||||
|
||||
SEQ_DEBUG(printf("timerdev_install: install a new timer.\n"));
|
||||
|
||||
ret = 0;
|
||||
tmd = NULL;
|
||||
scp = NULL;
|
||||
|
||||
scp = malloc(sizeof(*scp), M_DEVBUF, M_WAITOK | M_ZERO);
|
||||
if (scp == NULL) {
|
||||
ret = ENOMEM;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
tmd = create_timerdev_info_unit(&systmr_timerdev);
|
||||
if (tmd == NULL) {
|
||||
ret = ENOMEM;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
tmd->softc = scp;
|
||||
callout_init(&scp->timer, 0);
|
||||
|
||||
mtx_unlock(&tmd->mtx);
|
||||
|
||||
SEQ_DEBUG(printf("timerdev_install: installed a new timer, unit %d.\n", tmd->unit));
|
||||
|
||||
return (0);
|
||||
|
||||
fail:
|
||||
if (scp != NULL)
|
||||
free(scp, M_DEVBUF);
|
||||
if (tmd != NULL) {
|
||||
TAILQ_REMOVE(&timer_info, tmd, tmd_link);
|
||||
free(tmd, M_DEVBUF);
|
||||
}
|
||||
|
||||
SEQ_DEBUG(printf("timerdev_install: installation failed.\n"));
|
||||
|
||||
return (ret);
|
||||
}
|
||||
|
||||
/* Create a new timer device info structure. */
|
||||
timerdev_info *
|
||||
create_timerdev_info_unit(timerdev_info *tmdinf)
|
||||
{
|
||||
int unit;
|
||||
timerdev_info *tmd, *tmdnew;
|
||||
|
||||
/* XXX */
|
||||
if (!timerinfo_mtx_init) {
|
||||
timerinfo_mtx_init = 1;
|
||||
mtx_init(&timerinfo_mtx, "tmrinf", MTX_DEF);
|
||||
TAILQ_INIT(&timer_info);
|
||||
}
|
||||
|
||||
/* As malloc(9) might block, allocate timerdev_info now. */
|
||||
tmdnew = malloc(sizeof(timerdev_info), M_DEVBUF, M_WAITOK | M_ZERO);
|
||||
if (tmdnew == NULL)
|
||||
return NULL;
|
||||
bcopy(tmdinf, tmdnew, sizeof(timerdev_info));
|
||||
mtx_init(&tmdnew->mtx, "tmrmtx", MTX_DEF);
|
||||
|
||||
mtx_lock(&timerinfo_mtx);
|
||||
|
||||
ntimer++;
|
||||
|
||||
for (unit = 0 ; ; unit++) {
|
||||
TAILQ_FOREACH(tmd, &timer_info, tmd_link) {
|
||||
if (tmd->unit == unit)
|
||||
break;
|
||||
}
|
||||
if (tmd == NULL)
|
||||
break;
|
||||
}
|
||||
|
||||
tmdnew->unit = unit;
|
||||
mtx_lock(&tmdnew->mtx);
|
||||
tmd = TAILQ_FIRST(&timer_info);
|
||||
while (tmd != NULL) {
|
||||
if (tmd->prio < tmdnew->prio)
|
||||
break;
|
||||
tmd = TAILQ_NEXT(tmd, tmd_link);
|
||||
}
|
||||
if (tmd != NULL)
|
||||
TAILQ_INSERT_BEFORE(tmd, tmdnew, tmd_link);
|
||||
else
|
||||
TAILQ_INSERT_TAIL(&timer_info, tmdnew, tmd_link);
|
||||
|
||||
mtx_unlock(&timerinfo_mtx);
|
||||
|
||||
return (tmdnew);
|
||||
}
|
||||
|
||||
/*
|
||||
* a small utility function which, given a unit number, returns
|
||||
* a pointer to the associated timerdev_info struct.
|
||||
*/
|
||||
timerdev_info *
|
||||
get_timerdev_info_unit(int unit)
|
||||
{
|
||||
timerdev_info *tmd;
|
||||
|
||||
/* XXX */
|
||||
if (!timerinfo_mtx_init) {
|
||||
timerinfo_mtx_init = 1;
|
||||
mtx_init(&timerinfo_mtx, "tmrinf", MTX_DEF);
|
||||
TAILQ_INIT(&timer_info);
|
||||
}
|
||||
|
||||
mtx_lock(&timerinfo_mtx);
|
||||
TAILQ_FOREACH(tmd, &timer_info, tmd_link) {
|
||||
mtx_lock(&tmd->mtx);
|
||||
if (tmd->unit == unit && tmd->seq == NULL)
|
||||
break;
|
||||
mtx_unlock(&tmd->mtx);
|
||||
}
|
||||
mtx_unlock(&timerinfo_mtx);
|
||||
|
||||
return tmd;
|
||||
}
|
||||
|
||||
/*
|
||||
* a small utility function which returns a pointer
|
||||
* to the best preferred timerdev_info struct with
|
||||
* no sequencer.
|
||||
*/
|
||||
timerdev_info *
|
||||
get_timerdev_info(void)
|
||||
{
|
||||
timerdev_info *tmd;
|
||||
|
||||
/* XXX */
|
||||
if (!timerinfo_mtx_init) {
|
||||
timerinfo_mtx_init = 1;
|
||||
mtx_init(&timerinfo_mtx, "tmrinf", MTX_DEF);
|
||||
TAILQ_INIT(&timer_info);
|
||||
}
|
||||
|
||||
mtx_lock(&timerinfo_mtx);
|
||||
TAILQ_FOREACH(tmd, &timer_info, tmd_link) {
|
||||
mtx_lock(&tmd->mtx);
|
||||
if (tmd->seq == NULL)
|
||||
break;
|
||||
mtx_unlock(&tmd->mtx);
|
||||
}
|
||||
mtx_unlock(&timerinfo_mtx);
|
||||
|
||||
return tmd;
|
||||
}
|
||||
|
||||
|
||||
/* ARGSUSED */
|
||||
static void
|
||||
systmr_timer(void *d)
|
||||
{
|
||||
timerdev_info *tmd;
|
||||
struct systmr_timer_softc *scp;
|
||||
void *seq;
|
||||
|
||||
tmd = (timerdev_info *)d;
|
||||
scp = (struct systmr_timer_softc *)tmd->softc;
|
||||
seq = NULL;
|
||||
|
||||
mtx_lock(&tmd->mtx);
|
||||
|
||||
if (tmd->opened) {
|
||||
callout_reset(&scp->timer, 1, systmr_timer, tmd);
|
||||
|
||||
if (scp->running) {
|
||||
scp->ticks_cur = TMR2TICKS(scp, systmr_time());
|
||||
|
||||
if (CURTICKS(scp) >= scp->nexteventtime) {
|
||||
SEQ_DEBUG(printf("systmr_timer: CURTICKS %lu, call the sequencer.\n", CURTICKS(scp)));
|
||||
scp->nexteventtime = ULONG_MAX;
|
||||
seq = tmd->seq;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
mtx_unlock(&tmd->mtx);
|
||||
|
||||
if (seq != NULL)
|
||||
seq_timer(seq);
|
||||
}
|
||||
|
||||
static void
|
||||
systmr_reset(timerdev_info *tmd)
|
||||
{
|
||||
struct systmr_timer_softc *scp;
|
||||
|
||||
scp = (struct systmr_timer_softc *)tmd->softc;
|
||||
|
||||
mtx_assert(&tmd->mtx, MA_OWNED);
|
||||
|
||||
SEQ_DEBUG(printf("systmr_reset: unit %d.\n", tmd->unit));
|
||||
|
||||
scp->ticks_offset = 0;
|
||||
scp->ticks_base = scp->ticks_cur = TMR2TICKS(scp, systmr_time());
|
||||
|
||||
scp->nexteventtime = ULONG_MAX;
|
||||
scp->preveventtime = 0;
|
||||
}
|
||||
|
||||
static u_long
|
||||
systmr_time(void)
|
||||
{
|
||||
struct timeval timecopy;
|
||||
|
||||
getmicrotime(&timecopy);
|
||||
return timecopy.tv_usec / (1000000 / hz) + (u_long) timecopy.tv_sec * hz;
|
||||
}
|
||||
|
||||
|
||||
/* ARGSUSED */
|
||||
static int
|
||||
systmr_open(timerdev_info *tmd, int oflags, int devtype, struct thread *td)
|
||||
{
|
||||
struct systmr_timer_softc *scp;
|
||||
|
||||
scp = (struct systmr_timer_softc *)tmd->softc;
|
||||
|
||||
SEQ_DEBUG(printf("systmr_open: unit %d.\n", tmd->unit));
|
||||
|
||||
mtx_lock(&tmd->mtx);
|
||||
|
||||
if (tmd->opened) {
|
||||
mtx_unlock(&tmd->mtx);
|
||||
return (EBUSY);
|
||||
}
|
||||
|
||||
systmr_reset(tmd);
|
||||
scp->tempo = 60;
|
||||
scp->timebase = hz;
|
||||
tmd->opened = 1;
|
||||
|
||||
callout_reset(&scp->timer, 1, systmr_timer, tmd);
|
||||
|
||||
mtx_unlock(&tmd->mtx);
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
static int
|
||||
systmr_close(timerdev_info *tmd, int fflag, int devtype, struct thread *td)
|
||||
{
|
||||
struct systmr_timer_softc *scp;
|
||||
|
||||
scp = (struct systmr_timer_softc *)tmd->softc;
|
||||
|
||||
SEQ_DEBUG(printf("systmr_close: unit %d.\n", tmd->unit));
|
||||
|
||||
mtx_lock(&tmd->mtx);
|
||||
|
||||
tmd->opened = 0;
|
||||
scp->running = 0;
|
||||
|
||||
callout_stop(&scp->timer);
|
||||
|
||||
mtx_unlock(&tmd->mtx);
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
static int
|
||||
systmr_event(timerdev_info *tmd, u_char *ev)
|
||||
{
|
||||
struct systmr_timer_softc *scp;
|
||||
u_char cmd;
|
||||
u_long parm, t;
|
||||
int ret;
|
||||
void * seq;
|
||||
|
||||
scp = (struct systmr_timer_softc *)tmd->softc;
|
||||
cmd = ev[1];
|
||||
parm = *(int *)&ev[4];
|
||||
ret = MORE;
|
||||
|
||||
SEQ_DEBUG(printf("systmr_event: unit %d, cmd %s, parm %lu.\n",
|
||||
tmd->unit, midi_cmdname(cmd, cmdtab_timer), parm));
|
||||
|
||||
mtx_lock(&tmd->mtx);
|
||||
|
||||
switch (cmd) {
|
||||
case TMR_WAIT_REL:
|
||||
parm += scp->preveventtime;
|
||||
/* FALLTHRU */
|
||||
case TMR_WAIT_ABS:
|
||||
if (parm > 0) {
|
||||
if (parm <= CURTICKS(scp))
|
||||
break;
|
||||
t = parm;
|
||||
scp->nexteventtime = scp->preveventtime = t;
|
||||
ret = TIMERARMED;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
case TMR_START:
|
||||
systmr_reset(tmd);
|
||||
scp->running = 1;
|
||||
break;
|
||||
|
||||
case TMR_STOP:
|
||||
scp->running = 0;
|
||||
break;
|
||||
|
||||
case TMR_CONTINUE:
|
||||
scp->running = 1;
|
||||
break;
|
||||
|
||||
case TMR_TEMPO:
|
||||
if (parm > 0) {
|
||||
RANGE(parm, 8, 360);
|
||||
scp->ticks_offset += scp->ticks_cur
|
||||
- scp->ticks_base;
|
||||
scp->ticks_base = scp->ticks_cur;
|
||||
scp->tempo = parm;
|
||||
}
|
||||
break;
|
||||
|
||||
case TMR_ECHO:
|
||||
seq = tmd->seq;
|
||||
mtx_unlock(&tmd->mtx);
|
||||
seq_copytoinput(seq, ev, 8);
|
||||
mtx_lock(&tmd->mtx);
|
||||
break;
|
||||
}
|
||||
|
||||
mtx_unlock(&tmd->mtx);
|
||||
|
||||
SEQ_DEBUG(printf("systmr_event: timer %s.\n",
|
||||
ret == TIMERARMED ? "armed" : "not armed"));
|
||||
|
||||
return (ret);
|
||||
}
|
||||
|
||||
static int
|
||||
systmr_gettime(timerdev_info *tmd, u_long *t)
|
||||
{
|
||||
struct systmr_timer_softc *scp;
|
||||
int ret;
|
||||
|
||||
scp = (struct systmr_timer_softc *)tmd->softc;
|
||||
|
||||
SEQ_DEBUG(printf("systmr_gettime: unit %d.\n", tmd->unit));
|
||||
|
||||
mtx_lock(&tmd->mtx);
|
||||
|
||||
if (!tmd->opened || t == NULL) {
|
||||
ret = EINVAL;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
*t = CURTICKS(scp);
|
||||
SEQ_DEBUG(printf("systmr_gettime: ticks %lu.\n", *t));
|
||||
|
||||
fail:
|
||||
mtx_unlock(&tmd->mtx);
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
static int
|
||||
systmr_ioctl(timerdev_info *tmd, u_long cmd, caddr_t data, int fflag, struct thread *td)
|
||||
{
|
||||
struct systmr_timer_softc *scp;
|
||||
int ret, val;
|
||||
|
||||
scp = (struct systmr_timer_softc *)tmd->softc;
|
||||
ret = 0;
|
||||
|
||||
SEQ_DEBUG(printf("systmr_ioctl: unit %d, cmd %s.\n",
|
||||
tmd->unit, midi_cmdname(cmd, cmdtab_seqioctl)));
|
||||
|
||||
switch (cmd) {
|
||||
case SNDCTL_TMR_SOURCE:
|
||||
*(int *)data = TMR_INTERNAL;
|
||||
break;
|
||||
|
||||
case SNDCTL_TMR_START:
|
||||
mtx_lock(&tmd->mtx);
|
||||
systmr_reset(tmd);
|
||||
scp->running = 1;
|
||||
mtx_unlock(&tmd->mtx);
|
||||
break;
|
||||
|
||||
case SNDCTL_TMR_STOP:
|
||||
mtx_lock(&tmd->mtx);
|
||||
scp->running = 0;
|
||||
mtx_unlock(&tmd->mtx);
|
||||
break;
|
||||
|
||||
case SNDCTL_TMR_CONTINUE:
|
||||
mtx_lock(&tmd->mtx);
|
||||
scp->running = 1;
|
||||
mtx_unlock(&tmd->mtx);
|
||||
break;
|
||||
|
||||
case SNDCTL_TMR_TIMEBASE:
|
||||
val = *(int *)data;
|
||||
mtx_lock(&tmd->mtx);
|
||||
if (val > 0) {
|
||||
RANGE(val, 1, 1000);
|
||||
scp->timebase = val;
|
||||
}
|
||||
*(int *)data = scp->timebase;
|
||||
mtx_unlock(&tmd->mtx);
|
||||
SEQ_DEBUG(printf("systmr_ioctl: timebase %d.\n", *(int *)data));
|
||||
break;
|
||||
|
||||
case SNDCTL_TMR_TEMPO:
|
||||
val = *(int *)data;
|
||||
mtx_lock(&tmd->mtx);
|
||||
if (val > 0) {
|
||||
RANGE(val, 8, 360);
|
||||
scp->ticks_offset += scp->ticks_cur
|
||||
- scp->ticks_base;
|
||||
scp->ticks_base = scp->ticks_cur;
|
||||
scp->tempo = val;
|
||||
}
|
||||
*(int *)data = scp->tempo;
|
||||
SEQ_DEBUG(printf("systmr_ioctl: tempo %d.\n", *(int *)data));
|
||||
mtx_unlock(&tmd->mtx);
|
||||
break;
|
||||
|
||||
case SNDCTL_SEQ_CTRLRATE:
|
||||
val = *(int *)data;
|
||||
if (val > 0)
|
||||
ret = EINVAL;
|
||||
else {
|
||||
mtx_lock(&tmd->mtx);
|
||||
*(int *)data = ((scp->tempo * scp->timebase) + 30) / 60;
|
||||
mtx_unlock(&tmd->mtx);
|
||||
SEQ_DEBUG(printf("systmr_ioctl: ctrlrate %d.\n", *(int *)data));
|
||||
}
|
||||
break;
|
||||
|
||||
case SNDCTL_TMR_METRONOME:
|
||||
/* NOP. */
|
||||
break;
|
||||
|
||||
case SNDCTL_TMR_SELECT:
|
||||
/* NOP. */
|
||||
break;
|
||||
|
||||
default:
|
||||
ret = EINVAL;
|
||||
}
|
||||
|
||||
return (ret);
|
||||
}
|
||||
|
||||
static int
|
||||
systmr_armtimer(timerdev_info *tmd, u_long t)
|
||||
{
|
||||
struct systmr_timer_softc *scp;
|
||||
|
||||
scp = (struct systmr_timer_softc *)tmd->softc;
|
||||
|
||||
SEQ_DEBUG(printf("systmr_armtimer: unit %d, t %lu.\n", tmd->unit, t));
|
||||
|
||||
mtx_lock(&tmd->mtx);
|
||||
|
||||
if (t < 0)
|
||||
t = CURTICKS(scp) + 1;
|
||||
else if (t > CURTICKS(scp))
|
||||
scp->nexteventtime = scp->preveventtime = t;
|
||||
|
||||
mtx_unlock(&tmd->mtx);
|
||||
|
||||
return (0);
|
||||
}
|
80
sys/dev/sound/midi/timer.h
Normal file
80
sys/dev/sound/midi/timer.h
Normal file
@ -0,0 +1,80 @@
|
||||
/*
|
||||
* Include file for a midi timer.
|
||||
*
|
||||
* Copyright by Seigo Tanimura 2002.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*
|
||||
* $FreeBSD$
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef _TIMER_H_
|
||||
#define _TIMER_H_
|
||||
|
||||
typedef struct _timerdev_info timerdev_info;
|
||||
|
||||
typedef int (tmr_open_t)(timerdev_info *tmd, int oflags, int devtype, struct thread *td);
|
||||
typedef int (tmr_close_t)(timerdev_info *tmd, int fflag, int devtype, struct thread *td);
|
||||
typedef int (tmr_event_t)(timerdev_info *tmd, u_char *ev);
|
||||
typedef int (tmr_gettime_t)(timerdev_info *tmd, u_long *t);
|
||||
typedef int (tmr_ioctl_t)(timerdev_info *tmd, u_long cmd, caddr_t data, int fflag, struct thread *td);
|
||||
typedef int (tmr_armtimer_t)(timerdev_info *tmd, u_long t);
|
||||
|
||||
struct _timerdev_info {
|
||||
/*
|
||||
* the first part of the descriptor is filled up from a
|
||||
* template.
|
||||
*/
|
||||
char name[32];
|
||||
|
||||
int caps;
|
||||
int prio;
|
||||
|
||||
tmr_open_t *open;
|
||||
tmr_close_t *close;
|
||||
tmr_event_t *event;
|
||||
tmr_gettime_t *gettime;
|
||||
tmr_ioctl_t *ioctl;
|
||||
tmr_armtimer_t *armtimer;
|
||||
|
||||
|
||||
int unit;
|
||||
void *softc;
|
||||
void *seq;
|
||||
|
||||
/* The tailq entry of the next timer device. */
|
||||
TAILQ_ENTRY(_timerdev_info) tmd_link;
|
||||
|
||||
int opened;
|
||||
|
||||
struct mtx mtx;
|
||||
};
|
||||
|
||||
#ifdef _KERNEL
|
||||
int timerdev_install(void);
|
||||
timerdev_info *create_timerdev_info_unit(timerdev_info *tmdinf);
|
||||
timerdev_info *get_timerdev_info_unit(int unit);
|
||||
timerdev_info *get_timerdev_info(void);
|
||||
#endif /* _KERNEL */
|
||||
|
||||
#endif /* _TIMER_H_ */
|
Loading…
Reference in New Issue
Block a user