1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193
|
/** \file server/drivers/timing.h
* Utility header file for timing functions
*
* Made by Guillaume Filion, moved from the HD44780 driver.
*
* From hd44780.c:
* Modified July 2000 by Charles Steinkuehler to use one of 3 methods for delay
* timing. I/O reads, gettimeofday, and nanosleep. Of the three, nanosleep
* seems to work best, so that's what is set by default.
*/
/*-
* This file is released under the GNU General Public License. Refer to the
* COPYING file distributed with this package.
*
* Copyright (c) 2001 Guillaume Filion <gfk@logidac.com>
* 2001 Joris Robijn <joris@robijn.net>
* 2000 Charles Steinkuehler <cstein@newtek.com>
*/
#ifndef _TIMING_H
#define _TIMING_H
/*
* Uncomment one of the lines below this paragraph to select your desired
* delay generation mechanism.
* Mechanism DELAY_NANOSLEEP seems to provide the best performance.
* Mechanism DELAY_IOCALLS can be quite inaccurate.
* Mechanism DELAY_AUTOSELECT lets the system determine a mechanism, and is
* the default.
*/
#define DELAY_AUTOSELECT
//#define DELAY_GETTIMEOFDAY
//#define DELAY_NANOSLEEP
//#define DELAY_IOCALLS
#include <string.h>
#include <errno.h>
#include <unistd.h>
#ifdef HAVE_CONFIG_H
# include "config.h"
#endif
/* Autoselect... Does this always work well ? */
#ifdef DELAY_AUTOSELECT
# if defined HAVE_SCHED_H && defined HAVE_SCHED_SETSCHEDULER
# define DELAY_NANOSLEEP
# else
# define DELAY_GETTIMEOFDAY
# endif
#endif
/* Include the correct time.h stuff (regardless of selected mechanism) */
#if TIME_WITH_SYS_TIME
# include <sys/time.h>
# include <time.h>
#else
# if HAVE_SYS_TIME_H
# include <sys/time.h>
# else
# include <time.h>
# endif
#endif
/* Only one alternate delay method at a time, please ;-) */
#if defined DELAY_GETTIMEOFDAY
# undef DELAY_NANOSLEEP
# undef DELAY_IOCALLS
#elif defined DELAY_IOCALLS && defined HAVE_PCSTYLE_LPT_CONTROL
# undef DELAY_GETTIMEOFDAY
# undef DELAY_NANOSLEEP
# include "port.h"
#else /* assume DELAY_NANOSLEEP */
# undef DELAY_GETTIMEOFDAY
# undef DELAY_IOCALLS
# include <sched.h>
#endif
/*
* Convenience macros for operations on timevals. These are usually defined
* in sys/time.h. If your system does not have them, the defines from below
* are used.
*
* NOTE: `timercmp' does not work for >= or <=.
*/
#ifndef timerisset
# define timerisset(tvp) ((tvp)->tv_sec || (tvp)->tv_usec)
#endif
#ifndef timerclear
# define timerclear(tvp) ((tvp)->tv_sec = (tvp)->tv_usec = 0)
#endif
#ifndef timercmp
# define timercmp(a, b, CMP) \
(((a)->tv_sec == (b)->tv_sec) ? \
((a)->tv_usec CMP (b)->tv_usec) : \
((a)->tv_sec CMP (b)->tv_sec))
#endif
#ifndef timeradd
# define timeradd(a, b, result) \
do { \
(result)->tv_sec = (a)->tv_sec + (b)->tv_sec; \
(result)->tv_usec = (a)->tv_usec + (b)->tv_usec; \
if ((result)->tv_usec >= 1000000) \
{ \
++(result)->tv_sec; \
(result)->tv_usec -= 1000000; \
} \
} while (0)
#endif
#ifndef timersub
# define timersub(a, b, result) \
do { \
(result)->tv_sec = (a)->tv_sec - (b)->tv_sec; \
(result)->tv_usec = (a)->tv_usec - (b)->tv_usec; \
if ((result)->tv_usec < 0) { \
--(result)->tv_sec; \
(result)->tv_usec += 1000000; \
} \
} while (0)
#endif
/**
* Do necessary initialization for the selected waiting method.
* \return 0 if successful, -1 on error.
*/
static inline int
timing_init()
{
#if defined DELAY_NANOSLEEP
/* Change to Round-Robin scheduling for nanosleep */
{
/* Set priority to 1 */
struct sched_param param;
param.sched_priority=1;
if (( sched_setscheduler(0, SCHED_RR, ¶m)) == -1) {
return -1;
}
}
#elif defined DELAY_IOCALLS
if (port_access(0x3BD) == -1) {
return -1;
}
#endif
return 0;
}
/**
* Delay operation for some time using either gettimeofday (more or less an
* active waiting loop), nanosleep, or an I/O call.
* \param usecs Microsecond to pause
*/
static inline void
timing_uPause(int usecs)
{
#if defined DELAY_GETTIMEOFDAY
struct timeval current_time,delay_time,wait_time;
/* Get current time first thing */
gettimeofday(¤t_time,NULL);
/* Calculate when delay is over */
delay_time.tv_sec = 0;
delay_time.tv_usec = usecs;
timeradd(¤t_time,&delay_time,&wait_time);
do {
gettimeofday(¤t_time,NULL);
} while (timercmp(¤t_time,&wait_time,<));
#elif defined DELAY_NANOSLEEP
struct timespec delay_time,remaining;
delay_time.tv_sec = 0;
delay_time.tv_nsec = usecs * 1000;
while ( nanosleep(&delay_time,&remaining) == -1 )
{
delay_time.tv_sec = remaining.tv_sec;
delay_time.tv_nsec = remaining.tv_nsec;
}
#else /* using I/O timing */
int i;
for (i = 0; i < usecs; ++i)
port_in(0x3BD); /* Assuming every port I/O takes 1us */
#endif
}
#endif /* _TIMING_H */
|